diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp --- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp @@ -18,6 +18,7 @@ #include "../performance/MoveConstructorInitCheck.h" #include "../readability/UppercaseLiteralSuffixCheck.h" #include "CommandProcessorCheck.h" +#include "DefaultOperatorNewCheck.h" #include "DontModifyStdNamespaceCheck.h" #include "FloatLoopCounter.h" #include "LimitedRandomnessCheck.h" @@ -64,6 +65,8 @@ CheckFactories.registerCheck("cert-msc50-cpp"); CheckFactories.registerCheck( "cert-msc51-cpp"); + // MEM + CheckFactories.registerCheck("cert-mem57-cpp"); // C checkers // DCL diff --git a/clang-tools-extra/clang-tidy/cert/CMakeLists.txt b/clang-tools-extra/clang-tidy/cert/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/cert/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/cert/CMakeLists.txt @@ -3,6 +3,7 @@ add_clang_library(clangTidyCERTModule CERTTidyModule.cpp CommandProcessorCheck.cpp + DefaultOperatorNewCheck.cpp DontModifyStdNamespaceCheck.cpp FloatLoopCounter.cpp LimitedRandomnessCheck.cpp diff --git a/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewCheck.h b/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewCheck.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewCheck.h @@ -0,0 +1,35 @@ +//===--- DefaultOperatorNewCheck.h - clang-tidy -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_DEFAULTOPERATORNEWCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_DEFAULTOPERATORNEWCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace cert { + +/// Checks if an object of type with extended alignment is allocated by using +/// the default operator new. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/cert-mem57-cpp.html +class DefaultOperatorNewCheck : public ClangTidyCheck { +public: + DefaultOperatorNewCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace cert +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_DEFAULTOPERATORNEWCHECK_H diff --git a/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewCheck.cpp b/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewCheck.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewCheck.cpp @@ -0,0 +1,68 @@ +//===--- DefaultOperatorNewCheck.cpp - clang-tidy --------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DefaultOperatorNewCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace cert { + +void DefaultOperatorNewCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(cxxNewExpr().bind("new"), this); +} + +void DefaultOperatorNewCheck::check(const MatchFinder::MatchResult &Result) { + // Get the found 'new' expression. + const auto *NewExpr = Result.Nodes.getNodeAs("new"); + + // Skip placement new: This is a user-defined allocation. + if (NewExpr->getNumPlacementArgs() > 0) + return; + QualType T = NewExpr->getAllocatedType(); + // Dependent types do not have fixed alignment. + if (T->isDependentType()) + return; + const TagDecl *D = T->getAsTagDecl(); + // Alignment can not be obtained for undefined type. + if (!D || !D->getDefinition() || !D->isCompleteDefinition()) + return; + + ASTContext &Context = D->getASTContext(); + + // Check if no alignment was specified for the type. + if (!Context.isAlignmentRequired(T)) + return; + + // The user-specified alignment (in bits). + const unsigned SpecifiedAlignment = D->getMaxAlignment(); + // Double-check if no alignment was specified. + if (!SpecifiedAlignment) + return; + // The alignment used by default 'operator new' (in bits). + const unsigned DefaultAlignment = Context.getTargetInfo().getNewAlign(); + + const bool OverAligned = SpecifiedAlignment > DefaultAlignment; + const bool HasDefaultOperatorNew = + !NewExpr->getOperatorNew() || NewExpr->getOperatorNew()->isImplicit(); + + const unsigned CharWidth = Context.getTargetInfo().getCharWidth(); + if (HasDefaultOperatorNew && OverAligned) + diag(NewExpr->getBeginLoc(), + "allocation function returns a pointer with alignment %0 but the " + "over-aligned type being allocated requires alignment %1") + << (DefaultAlignment / CharWidth) << (SpecifiedAlignment / CharWidth); +} + +} // namespace cert +} // namespace tidy +} // namespace clang + diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -73,6 +73,12 @@ Finds instances where variables with static storage are initialized dynamically in header files. +- New :doc:`cert-mem57-cpp + ` check. + + Checks if an object of type with extended alignment is allocated by using + the default ``operator new``. + - New :doc:`linuxkernel-must-use-errs ` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert-mem57-cpp.rst b/clang-tools-extra/docs/clang-tidy/checks/cert-mem57-cpp.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/cert-mem57-cpp.rst @@ -0,0 +1,16 @@ +.. title:: clang-tidy - cert-mem57-cpp + +cert-mem57-cpp +============== + +This check flags uses of default ``operator new`` where the type has extended +alignment (an alignment greater than the fundamental alignment). (The default +``operator new`` is guaranteed to provide the correct alignmment if the +requested alignment is less or equal to the fundamental alignment). +Only cases are detected (by design) where the ``operator new`` is not +user-defined and is not a placement new (the reason is that in these cases we +assume that the user provided the correct memory allocation). + +This check corresponds to the CERT C++ Coding Standard rule +`MEM57-CPP. Avoid using default operator new for over-aligned types +`_. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -4,7 +4,6 @@ ================= .. toctree:: - abseil-duration-addition abseil-duration-comparison abseil-duration-conversion-cast @@ -98,93 +97,94 @@ cert-err61-cpp (redirects to misc-throw-by-value-catch-by-reference) cert-fio38-c (redirects to misc-non-copyable-objects) cert-flp30-c + cert-mem57-cpp cert-msc30-c (redirects to cert-msc50-cpp) cert-msc32-c (redirects to cert-msc51-cpp) cert-msc50-cpp cert-msc51-cpp cert-oop11-cpp (redirects to performance-move-constructor-init) cert-oop54-cpp (redirects to bugprone-unhandled-self-assignment) - clang-analyzer-core.CallAndMessage - clang-analyzer-core.DivideZero + clang-analyzer-core.CallAndMessage (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-core.DivideZero (redirects to https://clang.llvm.org/docs/analyzer/checkers) clang-analyzer-core.DynamicTypePropagation - clang-analyzer-core.NonNullParamChecker - clang-analyzer-core.NullDereference - clang-analyzer-core.StackAddressEscape - clang-analyzer-core.UndefinedBinaryOperatorResult - clang-analyzer-core.VLASize - clang-analyzer-core.uninitialized.ArraySubscript - clang-analyzer-core.uninitialized.Assign - clang-analyzer-core.uninitialized.Branch + clang-analyzer-core.NonNullParamChecker (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-core.NullDereference (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-core.StackAddressEscape (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-core.UndefinedBinaryOperatorResult (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-core.VLASize (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-core.uninitialized.ArraySubscript (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-core.uninitialized.Assign (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-core.uninitialized.Branch (redirects to https://clang.llvm.org/docs/analyzer/checkers) clang-analyzer-core.uninitialized.CapturedBlockVariable - clang-analyzer-core.uninitialized.UndefReturn + clang-analyzer-core.uninitialized.UndefReturn (redirects to https://clang.llvm.org/docs/analyzer/checkers) clang-analyzer-cplusplus.InnerPointer - clang-analyzer-cplusplus.Move - clang-analyzer-cplusplus.NewDelete - clang-analyzer-cplusplus.NewDeleteLeaks - clang-analyzer-deadcode.DeadStores - clang-analyzer-nullability.NullPassedToNonnull - clang-analyzer-nullability.NullReturnedFromNonnull - clang-analyzer-nullability.NullableDereferenced - clang-analyzer-nullability.NullablePassedToNonnull + clang-analyzer-cplusplus.Move (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-cplusplus.NewDelete (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-cplusplus.NewDeleteLeaks (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-deadcode.DeadStores (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-nullability.NullPassedToNonnull (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-nullability.NullReturnedFromNonnull (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-nullability.NullableDereferenced (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-nullability.NullablePassedToNonnull (redirects to https://clang.llvm.org/docs/analyzer/checkers) clang-analyzer-nullability.NullableReturnedFromNonnull - clang-analyzer-optin.cplusplus.UninitializedObject - clang-analyzer-optin.cplusplus.VirtualCall - clang-analyzer-optin.mpi.MPI-Checker + clang-analyzer-optin.cplusplus.UninitializedObject (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-optin.cplusplus.VirtualCall (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-optin.mpi.MPI-Checker (redirects to https://clang.llvm.org/docs/analyzer/checkers) clang-analyzer-optin.osx.OSObjectCStyleCast - clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker - clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker + clang-analyzer-optin.osx.cocoa.localizability.EmptyLocalizationContextChecker (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-optin.osx.cocoa.localizability.NonLocalizedStringChecker (redirects to https://clang.llvm.org/docs/analyzer/checkers) clang-analyzer-optin.performance.GCDAntipattern clang-analyzer-optin.performance.Padding clang-analyzer-optin.portability.UnixAPI - clang-analyzer-osx.API + clang-analyzer-osx.API (redirects to https://clang.llvm.org/docs/analyzer/checkers) clang-analyzer-osx.MIG clang-analyzer-osx.NumberObjectConversion clang-analyzer-osx.OSObjectRetainCount clang-analyzer-osx.ObjCProperty - clang-analyzer-osx.SecKeychainAPI - clang-analyzer-osx.cocoa.AtSync + clang-analyzer-osx.SecKeychainAPI (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-osx.cocoa.AtSync (redirects to https://clang.llvm.org/docs/analyzer/checkers) clang-analyzer-osx.cocoa.AutoreleaseWrite - clang-analyzer-osx.cocoa.ClassRelease - clang-analyzer-osx.cocoa.Dealloc - clang-analyzer-osx.cocoa.IncompatibleMethodTypes + clang-analyzer-osx.cocoa.ClassRelease (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-osx.cocoa.Dealloc (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-osx.cocoa.IncompatibleMethodTypes (redirects to https://clang.llvm.org/docs/analyzer/checkers) clang-analyzer-osx.cocoa.Loops clang-analyzer-osx.cocoa.MissingSuperCall - clang-analyzer-osx.cocoa.NSAutoreleasePool - clang-analyzer-osx.cocoa.NSError - clang-analyzer-osx.cocoa.NilArg + clang-analyzer-osx.cocoa.NSAutoreleasePool (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-osx.cocoa.NSError (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-osx.cocoa.NilArg (redirects to https://clang.llvm.org/docs/analyzer/checkers) clang-analyzer-osx.cocoa.NonNilReturnValue - clang-analyzer-osx.cocoa.ObjCGenerics - clang-analyzer-osx.cocoa.RetainCount + clang-analyzer-osx.cocoa.ObjCGenerics (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-osx.cocoa.RetainCount (redirects to https://clang.llvm.org/docs/analyzer/checkers) clang-analyzer-osx.cocoa.RunLoopAutoreleaseLeak - clang-analyzer-osx.cocoa.SelfInit - clang-analyzer-osx.cocoa.SuperDealloc - clang-analyzer-osx.cocoa.UnusedIvars - clang-analyzer-osx.cocoa.VariadicMethodTypes - clang-analyzer-osx.coreFoundation.CFError - clang-analyzer-osx.coreFoundation.CFNumber - clang-analyzer-osx.coreFoundation.CFRetainRelease - clang-analyzer-osx.coreFoundation.containers.OutOfBounds - clang-analyzer-osx.coreFoundation.containers.PointerSizedValues - clang-analyzer-security.FloatLoopCounter - clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling - clang-analyzer-security.insecureAPI.UncheckedReturn - clang-analyzer-security.insecureAPI.bcmp - clang-analyzer-security.insecureAPI.bcopy - clang-analyzer-security.insecureAPI.bzero - clang-analyzer-security.insecureAPI.getpw - clang-analyzer-security.insecureAPI.gets - clang-analyzer-security.insecureAPI.mkstemp - clang-analyzer-security.insecureAPI.mktemp - clang-analyzer-security.insecureAPI.rand - clang-analyzer-security.insecureAPI.strcpy - clang-analyzer-security.insecureAPI.vfork - clang-analyzer-unix.API - clang-analyzer-unix.Malloc - clang-analyzer-unix.MallocSizeof - clang-analyzer-unix.MismatchedDeallocator - clang-analyzer-unix.Vfork - clang-analyzer-unix.cstring.BadSizeArg - clang-analyzer-unix.cstring.NullArg + clang-analyzer-osx.cocoa.SelfInit (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-osx.cocoa.SuperDealloc (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-osx.cocoa.UnusedIvars (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-osx.cocoa.VariadicMethodTypes (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-osx.coreFoundation.CFError (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-osx.coreFoundation.CFNumber (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-osx.coreFoundation.CFRetainRelease (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-osx.coreFoundation.containers.OutOfBounds (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-osx.coreFoundation.containers.PointerSizedValues (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-security.FloatLoopCounter (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-security.insecureAPI.UncheckedReturn (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-security.insecureAPI.bcmp (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-security.insecureAPI.bcopy (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-security.insecureAPI.bzero (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-security.insecureAPI.getpw (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-security.insecureAPI.gets (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-security.insecureAPI.mkstemp (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-security.insecureAPI.mktemp (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-security.insecureAPI.rand (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-security.insecureAPI.strcpy (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-security.insecureAPI.vfork (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-unix.API (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-unix.Malloc (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-unix.MallocSizeof (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-unix.MismatchedDeallocator (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-unix.Vfork (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-unix.cstring.BadSizeArg (redirects to https://clang.llvm.org/docs/analyzer/checkers) + clang-analyzer-unix.cstring.NullArg (redirects to https://clang.llvm.org/docs/analyzer/checkers) clang-analyzer-valist.CopyToSelf clang-analyzer-valist.Uninitialized clang-analyzer-valist.Unterminated diff --git a/clang-tools-extra/test/clang-tidy/cert-mem57-cpp.cpp b/clang-tools-extra/test/clang-tidy/cert-mem57-cpp.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/cert-mem57-cpp.cpp @@ -0,0 +1,39 @@ +// RUN: %check_clang_tidy %s cert-mem57-cpp %t + +namespace std { +typedef __typeof(sizeof(int)) size_t; +void *aligned_alloc(size_t, size_t); +void free(void *); +} // namespace std + +struct alignas(32) Vector1 { + char elems[32]; +}; + +struct Vector2 { + char elems[32]; +}; + +struct alignas(32) Vector3 { + char elems[32]; + static void *operator new(std::size_t nbytes) noexcept(true) { + return std::aligned_alloc(alignof(Vector3), nbytes); + } + static void operator delete(void *p) { + std::free(p); + } +}; + +struct alignas(8) Vector4 { + char elems[32]; +}; + +void f() { + auto *V1 = new Vector1; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: allocation function returns a pointer with alignment 16 but the over-aligned type being allocated requires alignment 32 [cert-mem57-cpp] + auto *V2 = new Vector2; + auto *V3 = new Vector3; + auto *V4 = new Vector4; + auto *V1_Arr = new Vector1[2]; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: allocation function returns a pointer with alignment 16 but the over-aligned type being allocated requires alignment 32 [cert-mem57-cpp] +}