-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang-tidy] Add bugprone-pointer-arithmetic-on-polymorphic-object
check
#91951
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
69cbd3d
Add `bugprone-virtual-arithmetic` check
Discookie 47068bd
Display the classname that has the virtual function
Discookie df2e3f1
Rename check to `bugprone-pointer-arithmetic-on-polymorphic-object`
Discookie fe0d5a7
Add `MatchInheritedVirtualFunctions` option
Discookie f373922
Restrict to C++
Discookie a29c9cd
Update check message and comments
Discookie 914f349
Add support for type aliases
Discookie 801d7ec
Add tests for prefix `++`
Discookie e5dc6b2
Add comment about the UB's cause
Discookie dc7e63c
Exclude final classes
Discookie 6415b14
Add CERT alias
Discookie 6a4f75a
Use `isAbstract` matcher for inherited pure functions
Discookie d0e5bc2
Pipe source range into diag message
Discookie 3c2508c
Docs fixes
Discookie 225804a
Minor fixes
Discookie 7b87e77
Merge branch 'main' into ctr56-tidy
Discookie 11d838e
Order typo
Discookie c7f2391
Make check respect TK_IgnoreUnlessSpelledInSource
Discookie 34370b1
Make check description consistent
Discookie 411f815
Make IgnoreInheritedVirtualFunctions default false
Discookie 07a4e9b
Fix side effects of TK_IgnoreUnlessSpelledInSource
Discookie 4dac982
Better warning text
Discookie 7cd17bb
Fix diag message typos
Discookie File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 differs from the pointer type") | ||
<< PointeeDecl << PointerExpr->getSourceRange(); | ||
} | ||
|
||
} // namespace clang::tidy::bugprone |
41 changes: 41 additions & 0 deletions
41
clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
|
||
Discookie marked this conversation as resolved.
Show resolved
Hide resolved
|
||
private: | ||
const bool IgnoreInheritedVirtualFunctions; | ||
}; | ||
PiotrZSL marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
} // namespace clang::tidy::bugprone | ||
|
||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_POINTERARITHMETICONPOLYMORPHICOBJECTCHECK_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
...ra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
different from its dynamic type is undefined behavior, as the two types could | ||
have different 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 different, | ||
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 differs 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. | ||
Discookie marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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>`_. |
10 changes: 10 additions & 0 deletions
10
clang-tools-extra/docs/clang-tidy/checks/cert/ctr56-cpp.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.