Author: Discookie Date: 2024-07-04T13:44:31Z New Revision: f329e3ed9070aee3f4c0ebc80ed62f5c4b645d73
URL: https://github.com/llvm/llvm-project/commit/f329e3ed9070aee3f4c0ebc80ed62f5c4b645d73 DIFF: https://github.com/llvm/llvm-project/commit/f329e3ed9070aee3f4c0ebc80ed62f5c4b645d73.diff LOG: [clang-tidy] Add `bugprone-pointer-arithmetic-on-polymorphic-object` check (#91951) Finds pointer arithmetic on classes that declare a virtual function. This check corresponds to the SEI Cert rule [CTR56-CPP: Do not use pointer arithmetic on polymorphic objects](https://wiki.sei.cmu.edu/confluence/display/cplusplus/CTR56-CPP.+Do+not+use+pointer+arithmetic+on+polymorphic+objects). ```cpp struct Base { virtual void ~Base(); }; struct Derived : public Base {}; void foo(Base *b) { b += 1; // passing `Derived` to `foo()` results in UB } ``` [Results on open-source projects](https://codechecker-demo.eastus.cloudapp.azure.com/Default/runs?run=Discookie-ctr56-with-classnames). Most of the Qtbase reports are from having a `virtual override` declaration, and the LLVM reports are true positives, as far as I can tell. Added: clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst clang-tools-extra/docs/clang-tidy/checks/cert/ctr56-cpp.rst clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp Modified: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/list.rst Removed: ################################################################################ diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index 1b92d2e60cc17..689eb92a3d8d1 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -51,6 +51,7 @@ #include "NotNullTerminatedResultCheck.h" #include "OptionalValueConversionCheck.h" #include "ParentVirtualCallCheck.h" +#include "PointerArithmeticOnPolymorphicObjectCheck.h" #include "PosixReturnCheck.h" #include "RedundantBranchConditionCheck.h" #include "ReservedIdentifierCheck.h" @@ -171,6 +172,8 @@ class BugproneModule : public ClangTidyModule { "bugprone-multiple-statement-macro"); CheckFactories.registerCheck<OptionalValueConversionCheck>( "bugprone-optional-value-conversion"); + CheckFactories.registerCheck<PointerArithmeticOnPolymorphicObjectCheck>( + "bugprone-pointer-arithmetic-on-polymorphic-object"); CheckFactories.registerCheck<RedundantBranchConditionCheck>( "bugprone-redundant-branch-condition"); CheckFactories.registerCheck<cppcoreguidelines::NarrowingConversionsCheck>( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index 2d303191f8865..cb0d8ae98bac5 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -48,6 +48,7 @@ add_clang_library(clangTidyBugproneModule NotNullTerminatedResultCheck.cpp OptionalValueConversionCheck.cpp ParentVirtualCallCheck.cpp + PointerArithmeticOnPolymorphicObjectCheck.cpp PosixReturnCheck.cpp RedundantBranchConditionCheck.cpp ReservedIdentifierCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp new file mode 100644 index 0000000000000..6e6ad10fabbb3 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp @@ -0,0 +1,81 @@ +//===--- PointerArithmeticOnPolymorphicObjectCheck.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 "PointerArithmeticOnPolymorphicObjectCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +namespace { +AST_MATCHER(CXXRecordDecl, isAbstract) { return Node.isAbstract(); } +AST_MATCHER(CXXRecordDecl, isPolymorphic) { return Node.isPolymorphic(); } +} // namespace + +PointerArithmeticOnPolymorphicObjectCheck:: + PointerArithmeticOnPolymorphicObjectCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + IgnoreInheritedVirtualFunctions( + Options.get("IgnoreInheritedVirtualFunctions", false)) {} + +void PointerArithmeticOnPolymorphicObjectCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoreInheritedVirtualFunctions", + IgnoreInheritedVirtualFunctions); +} + +void PointerArithmeticOnPolymorphicObjectCheck::registerMatchers( + MatchFinder *Finder) { + const auto PolymorphicPointerExpr = + expr(hasType(hasCanonicalType(pointerType(pointee(hasCanonicalType( + hasDeclaration(cxxRecordDecl(unless(isFinal()), isPolymorphic()) + .bind("pointee")))))))) + .bind("pointer"); + + const auto PointerExprWithVirtualMethod = + expr(hasType(hasCanonicalType( + pointerType(pointee(hasCanonicalType(hasDeclaration( + cxxRecordDecl( + unless(isFinal()), + anyOf(hasMethod(isVirtualAsWritten()), isAbstract())) + .bind("pointee")))))))) + .bind("pointer"); + + const auto SelectedPointerExpr = IgnoreInheritedVirtualFunctions + ? PointerExprWithVirtualMethod + : PolymorphicPointerExpr; + + const auto ArraySubscript = arraySubscriptExpr(hasBase(SelectedPointerExpr)); + + const auto BinaryOperators = + binaryOperator(hasAnyOperatorName("+", "-", "+=", "-="), + hasEitherOperand(SelectedPointerExpr)); + + const auto UnaryOperators = unaryOperator( + hasAnyOperatorName("++", "--"), hasUnaryOperand(SelectedPointerExpr)); + + Finder->addMatcher(ArraySubscript, this); + Finder->addMatcher(BinaryOperators, this); + Finder->addMatcher(UnaryOperators, this); +} + +void PointerArithmeticOnPolymorphicObjectCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *PointerExpr = Result.Nodes.getNodeAs<Expr>("pointer"); + const auto *PointeeDecl = Result.Nodes.getNodeAs<CXXRecordDecl>("pointee"); + + diag(PointerExpr->getBeginLoc(), + "pointer arithmetic on polymorphic object of type %0 can result in " + "undefined behavior if the dynamic type diff ers from the pointer type") + << PointeeDecl << PointerExpr->getSourceRange(); +} + +} // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h new file mode 100644 index 0000000000000..84f2d8e74ba87 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h @@ -0,0 +1,41 @@ +//===--- PointerArithmeticOnPolymorphicObjectCheck.h ------------*- 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_BUGPRONE_POINTERARITHMETICONPOLYMORPHICOBJECTCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_POINTERARITHMETICONPOLYMORPHICOBJECTCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::bugprone { + +/// Finds pointer arithmetic performed on classes that contain a +/// virtual function. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.html +class PointerArithmeticOnPolymorphicObjectCheck : public ClangTidyCheck { +public: + PointerArithmeticOnPolymorphicObjectCheck(StringRef Name, + ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + std::optional<TraversalKind> getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } + +private: + const bool IgnoreInheritedVirtualFunctions; +}; + +} // namespace clang::tidy::bugprone + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_POINTERARITHMETICONPOLYMORPHICOBJECTCHECK_H diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp index 00370ee9b3004..ffb62b409b29b 100644 --- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp @@ -10,6 +10,7 @@ #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" #include "../bugprone/BadSignalToKillThreadCheck.h" +#include "../bugprone/PointerArithmeticOnPolymorphicObjectCheck.h" #include "../bugprone/ReservedIdentifierCheck.h" #include "../bugprone/SignalHandlerCheck.h" #include "../bugprone/SignedCharMisuseCheck.h" @@ -238,6 +239,10 @@ class CERTModule : public ClangTidyModule { // CON CheckFactories.registerCheck<bugprone::SpuriouslyWakeUpFunctionsCheck>( "cert-con54-cpp"); + // CTR + CheckFactories + .registerCheck<bugprone::PointerArithmeticOnPolymorphicObjectCheck>( + "cert-ctr56-cpp"); // DCL CheckFactories.registerCheck<VariadicFunctionDefCheck>("cert-dcl50-cpp"); CheckFactories.registerCheck<bugprone::ReservedIdentifierCheck>( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index fe819731f38b9..e570c8184f8b0 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -137,6 +137,11 @@ New checks Detects error-prone Curiously Recurring Template Pattern usage, when the CRTP can be constructed outside itself and the derived class. +- New :doc:`bugprone-pointer-arithmetic-on-polymorphic-object + <clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object>` check. + + Finds pointer arithmetic performed on classes that contain a virtual function. + - New :doc:`bugprone-return-const-ref-from-parameter <clang-tidy/checks/bugprone/return-const-ref-from-parameter>` check. @@ -199,6 +204,11 @@ New checks New check aliases ^^^^^^^^^^^^^^^^^ +- New alias :doc:`cert-ctr56-cpp <clang-tidy/checks/cert/ctr56-cpp>` to + :doc:`bugprone-pointer-arithmetic-on-polymorphic-object + <clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object>` + was added. + - New alias :doc:`cert-int09-c <clang-tidy/checks/cert/int09-c>` to :doc:`readability-enum-initial-value <clang-tidy/checks/readability/enum-initial-value>` was added. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst new file mode 100644 index 0000000000000..1884acd5f12b3 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst @@ -0,0 +1,68 @@ +.. title:: clang-tidy - bugprone-pointer-arithmetic-on-polymorphic-object + +bugprone-pointer-arithmetic-on-polymorphic-object +================================================= + +Finds pointer arithmetic performed on classes that contain a virtual function. + +Pointer arithmetic on polymorphic objects where the pointer's static type is + diff erent from its dynamic type is undefined behavior, as the two types could +have diff erent sizes, and thus the vtable pointer could point to an +invalid address. + +Finding pointers where the static type contains a virtual member function is a +good heuristic, as the pointer is likely to point to a diff erent, +derived object. + +Example: + +.. code-block:: c++ + + struct Base { + virtual void ~Base(); + }; + + struct Derived : public Base {}; + + void foo() { + Base *b = new Derived[10]; + + b += 1; + // warning: pointer arithmetic on class that declares a virtual function can + // result in undefined behavior if the dynamic type diff ers from the + // pointer type + + delete[] static_cast<Derived*>(b); + } + +Options +------- + +.. option:: IgnoreInheritedVirtualFunctions + + When `true`, objects that only inherit a virtual function are not checked. + Classes that do not declare a new virtual function are excluded + by default, as they make up the majority of false positives. + Default: `false`. + + .. code-block:: c++ + + void bar() { + Base *b = new Base[10]; + b += 1; // warning, as Base declares a virtual destructor + + delete[] b; + + Derived *d = new Derived[10]; // Derived overrides the destructor, and + // declares no other virtual functions + d += 1; // warning only if IgnoreVirtualDeclarationsOnly is set to false + + delete[] d; + } + +References +---------- + +This check corresponds to the SEI Cert rule +`CTR56-CPP. Do not use pointer arithmetic on polymorphic objects +<https://wiki.sei.cmu.edu/confluence/display/cplusplus/CTR56-CPP.+Do+not+use+pointer+arithmetic+on+polymorphic+objects>`_. diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert/ctr56-cpp.rst b/clang-tools-extra/docs/clang-tidy/checks/cert/ctr56-cpp.rst new file mode 100644 index 0000000000000..e42acbe552359 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/cert/ctr56-cpp.rst @@ -0,0 +1,10 @@ +.. title:: clang-tidy - cert-ctr56-cpp +.. meta:: + :http-equiv=refresh: 5;URL=../bugprone/pointer-arithmetic-on-polymorphic-object.html + +cert-ctr56-cpp +============== + +The `cert-ctr56-cpp` check is an alias, please see +:doc:`bugprone-pointer-arithmetic-on-polymorphic-object +<../bugprone/pointer-arithmetic-on-polymorphic-object>` for more information. \ No newline at end of file diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index a698cecc0825c..9671f3895f5d3 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -157,6 +157,7 @@ Clang-Tidy Checks :doc:`bugprone-unused-raii <bugprone/unused-raii>`, "Yes" :doc:`bugprone-unused-return-value <bugprone/unused-return-value>`, :doc:`bugprone-use-after-move <bugprone/use-after-move>`, + :doc:`bugprone-pointer-arithmetic-on-polymorphic-object <bugprone/pointer-arithmetic-on-polymorphic-object>`, :doc:`bugprone-virtual-near-miss <bugprone/virtual-near-miss>`, "Yes" :doc:`cert-dcl50-cpp <cert/dcl50-cpp>`, :doc:`cert-dcl58-cpp <cert/dcl58-cpp>`, diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp new file mode 100644 index 0000000000000..caf24f79ad2d8 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp @@ -0,0 +1,140 @@ +// RUN: %check_clang_tidy %s bugprone-pointer-arithmetic-on-polymorphic-object %t -- + +class Base { +public: + virtual ~Base() {} +}; + +class Derived : public Base {}; + +class FinalDerived final : public Base {}; + +class AbstractBase { +public: + virtual void f() = 0; + virtual ~AbstractBase() {} +}; + +class AbstractInherited : public AbstractBase {}; + +class AbstractOverride : public AbstractInherited { +public: + void f() override {} +}; + +void operators() { + Base *b = new Derived[10]; + + b += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type diff ers from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object] + + b = b + 1; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type diff ers from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object] + + b++; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type diff ers from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object] + + --b; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type diff ers from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object] + + b[1]; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type diff ers from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object] + + delete[] static_cast<Derived*>(b); +} + +void subclassWarnings() { + Base *b = new Base[10]; + + // False positive that's impossible to distinguish without + // path-sensitive analysis, but the code is bug-prone regardless. + b += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' + + delete[] b; + + // Common false positive is a class that overrides all parent functions. + // Is a warning because of the check configuration. + Derived *d = new Derived[10]; + + d += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Derived' + + delete[] d; + + // Final classes cannot have a dynamic type. + FinalDerived *fd = new FinalDerived[10]; + + fd += 1; + // no-warning + + delete[] fd; +} + +void abstractWarnings() { + // Classes with an abstract member funtion are always matched. + AbstractBase *ab = new AbstractOverride[10]; + + ab += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'AbstractBase' + + delete[] static_cast<AbstractOverride*>(ab); + + AbstractInherited *ai = new AbstractOverride[10]; + + ai += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'AbstractInherited' + + delete[] static_cast<AbstractOverride*>(ai); + + // Is a warning because of the check configuration. + AbstractOverride *ao = new AbstractOverride[10]; + + ao += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'AbstractOverride' + + delete[] ao; +} + +template <typename T> +void templateWarning(T *t) { + // FIXME: Tidy doesn't support template instantiation locations properly. + t += 1; + // no-warning +} + +void functionArgument(Base *b) { + b += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' + + templateWarning(b); +} + +using BaseAlias = Base; +using DerivedAlias = Derived; +using FinalDerivedAlias = FinalDerived; + +using BasePtr = Base*; +using DerivedPtr = Derived*; +using FinalDerivedPtr = FinalDerived*; + +void typeAliases(BaseAlias *b, DerivedAlias *d, FinalDerivedAlias *fd, + BasePtr bp, DerivedPtr dp, FinalDerivedPtr fdp) { + b += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' + + d += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Derived' + + fd += 1; + // no-warning + + bp += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' + + dp += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Derived' + + fdp += 1; + // no-warning +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp new file mode 100644 index 0000000000000..48757bbc9b10e --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp @@ -0,0 +1,141 @@ +// RUN: %check_clang_tidy %s bugprone-pointer-arithmetic-on-polymorphic-object %t -- \ +// RUN: -config="{CheckOptions: \ +// RUN: {bugprone-pointer-arithmetic-on-polymorphic-object.IgnoreInheritedVirtualFunctions: true}}" + +class Base { +public: + virtual ~Base() {} +}; + +class Derived : public Base {}; + +class FinalDerived final : public Base {}; + +class AbstractBase { +public: + virtual void f() = 0; + virtual ~AbstractBase() {} +}; + +class AbstractInherited : public AbstractBase {}; + +class AbstractOverride : public AbstractInherited { +public: + void f() override {} +}; + +void operators() { + Base *b = new Derived[10]; + + b += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type diff ers from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object] + + b = b + 1; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type diff ers from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object] + + b++; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type diff ers from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object] + + --b; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type diff ers from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object] + + b[1]; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' can result in undefined behavior if the dynamic type diff ers from the pointer type [bugprone-pointer-arithmetic-on-polymorphic-object] + + delete[] static_cast<Derived*>(b); +} + +void subclassWarnings() { + Base *b = new Base[10]; + + // False positive that's impossible to distinguish without + // path-sensitive analysis, but the code is bug-prone regardless. + b += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' + + delete[] b; + + // Common false positive is a class that overrides all parent functions. + Derived *d = new Derived[10]; + + d += 1; + // no-warning + + delete[] d; + + // Final classes cannot have a dynamic type. + FinalDerived *fd = new FinalDerived[10]; + + fd += 1; + // no-warning + + delete[] fd; +} + +void abstractWarnings() { + // Classes with an abstract member funtion are always matched. + AbstractBase *ab = new AbstractOverride[10]; + + ab += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'AbstractBase' + + delete[] static_cast<AbstractOverride*>(ab); + + AbstractInherited *ai = new AbstractOverride[10]; + + ai += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'AbstractInherited' + + delete[] static_cast<AbstractOverride*>(ai); + + // If all abstract member functions are overridden, the class is not matched. + AbstractOverride *ao = new AbstractOverride[10]; + + ao += 1; + // no-warning + + delete[] ao; +} + +template <typename T> +void templateWarning(T *t) { + // FIXME: Tidy doesn't support template instantiation locations properly. + t += 1; + // no-warning +} + +void functionArgument(Base *b) { + b += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' + + templateWarning(b); +} + +using BaseAlias = Base; +using DerivedAlias = Derived; +using FinalDerivedAlias = FinalDerived; + +using BasePtr = Base*; +using DerivedPtr = Derived*; +using FinalDerivedPtr = FinalDerived*; + +void typeAliases(BaseAlias *b, DerivedAlias *d, FinalDerivedAlias *fd, + BasePtr bp, DerivedPtr dp, FinalDerivedPtr fdp) { + b += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' + + d += 1; + // no-warning + + fd += 1; + // no-warning + + bp += 1; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base' + + dp += 1; + // no-warning + + fdp += 1; + // no-warning +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits