[clang-tools-extra] [clang-tidy] Add `bugprone-pointer-arithmetic-on-polymorphic-object` check (PR #91951)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 18 02:24:10 PDT 2024
https://github.com/Discookie updated https://github.com/llvm/llvm-project/pull/91951
>From 69cbd3da19eb0f8eb6758782b46daf99b5b79ea4 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Mon, 6 May 2024 06:11:58 +0000
Subject: [PATCH 01/15] Add `bugprone-virtual-arithmetic` check
Finds pointer arithmetic on classes that declare a virtual function.
---
.../bugprone/BugproneTidyModule.cpp | 3 ++
.../clang-tidy/bugprone/CMakeLists.txt | 1 +
.../bugprone/VirtualArithmeticCheck.cpp | 46 +++++++++++++++++
.../bugprone/VirtualArithmeticCheck.h | 30 +++++++++++
.../checks/bugprone/virtual-arithmetic.rst | 50 +++++++++++++++++++
.../docs/clang-tidy/checks/list.rst | 1 +
.../checkers/bugprone/virtual-arithmetic.cpp | 45 +++++++++++++++++
7 files changed, 176 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/virtual-arithmetic.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 1b92d2e60cc17..813f6720074ae 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -91,6 +91,7 @@
#include "UnusedRaiiCheck.h"
#include "UnusedReturnValueCheck.h"
#include "UseAfterMoveCheck.h"
+#include "VirtualArithmeticCheck.h"
#include "VirtualNearMissCheck.h"
namespace clang::tidy {
@@ -254,6 +255,8 @@ class BugproneModule : public ClangTidyModule {
CheckFactories.registerCheck<UnusedReturnValueCheck>(
"bugprone-unused-return-value");
CheckFactories.registerCheck<UseAfterMoveCheck>("bugprone-use-after-move");
+ CheckFactories.registerCheck<VirtualArithmeticCheck>(
+ "bugprone-virtual-arithmetic");
CheckFactories.registerCheck<VirtualNearMissCheck>(
"bugprone-virtual-near-miss");
}
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index 2d303191f8865..ec1f3231e7990 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -87,6 +87,7 @@ add_clang_library(clangTidyBugproneModule
UnusedRaiiCheck.cpp
UnusedReturnValueCheck.cpp
UseAfterMoveCheck.cpp
+ VirtualArithmeticCheck.cpp
VirtualNearMissCheck.cpp
LINK_LIBS
diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
new file mode 100644
index 0000000000000..57347af2b5881
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
@@ -0,0 +1,46 @@
+//===--- VirtualArithmeticCheck.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 "VirtualArithmeticCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+void VirtualArithmeticCheck::registerMatchers(MatchFinder *Finder) {
+ const auto PointerExprWithVirtualMethod =
+ expr(hasType(pointerType(pointee(hasDeclaration(
+ cxxRecordDecl(hasMethod(isVirtualAsWritten())))))))
+ .bind("pointer");
+
+ const auto ArraySubscript =
+ arraySubscriptExpr(hasBase(PointerExprWithVirtualMethod));
+
+ const auto BinaryOperators =
+ binaryOperator(hasAnyOperatorName("+", "-", "+=", "-="),
+ hasEitherOperand(PointerExprWithVirtualMethod));
+
+ const auto UnaryOperators =
+ unaryOperator(hasAnyOperatorName("++", "--"),
+ hasUnaryOperand(PointerExprWithVirtualMethod));
+
+ Finder->addMatcher(
+ expr(anyOf(ArraySubscript, BinaryOperators, UnaryOperators)), this);
+}
+
+void VirtualArithmeticCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *PointerExpr = Result.Nodes.getNodeAs<Expr>("pointer");
+
+ diag(PointerExpr->getBeginLoc(),
+ "pointer arithmetic on class that declares a virtual function, "
+ "undefined behavior if the pointee is a different class");
+}
+
+} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.h b/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.h
new file mode 100644
index 0000000000000..6a5f86a391747
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.h
@@ -0,0 +1,30 @@
+//===--- VirtualArithmeticCheck.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_BUGPRONE_VIRTUAL_ARITHMETIC_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_VIRTUAL_ARITHMETIC_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// Finds pointer arithmetic on classes that declare a virtual function.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/virtual-arithmetic.html
+class VirtualArithmeticCheck : public ClangTidyCheck {
+public:
+ VirtualArithmeticCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace clang::tidy::bugprone
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_VIRTUAL_ARITHMETIC_H
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/virtual-arithmetic.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/virtual-arithmetic.rst
new file mode 100644
index 0000000000000..69d43e13392be
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/virtual-arithmetic.rst
@@ -0,0 +1,50 @@
+.. title:: clang-tidy - bugprone-virtual-arithmetic
+
+bugprone-virtual-arithmetic
+===========================
+
+Warn if pointer arithmetic is performed on a class that declares a
+virtual function.
+
+Pointer arithmetic on polymorphic objects where the pointer's static type is
+different from its dynamic type is undefined behavior.
+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 class.
+
+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>`_.
+
+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, undefined behavior if the pointee is a different class
+
+ delete[] static_cast<Derived*>(b);
+ }
+
+Classes that do not declare a new virtual function are excluded,
+as they make up the majority of false positives.
+
+.. code-block:: c++
+
+ void bar() {
+ Base *b = new Base[10];
+ b += 1; // warning, as Base has a virtual destructor
+
+ delete[] b;
+
+ Derived *d = new Derived[10];
+ d += 1; // no warning, as Derived overrides the destructor
+
+ delete[] d;
+ }
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 5cdaf9e35b6ac..ba1e5cafa6e47 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-virtual-arithmetic <bugprone/virtual-arithmetic>`,
: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/virtual-arithmetic.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
new file mode 100644
index 0000000000000..d772112293cbc
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
@@ -0,0 +1,45 @@
+// RUN: %check_clang_tidy %s bugprone-virtual-arithmetic %t
+
+class Base {
+public:
+ virtual ~Base() {}
+};
+
+class Derived : public Base {};
+
+void operators() {
+ Base *b = new Derived[10];
+
+ b += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+
+ b = b + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+
+ b++;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+
+ b[1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+
+ 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 class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+
+ delete[] b;
+
+ // Common false positive is a class that overrides all parent functions.
+ Derived *d = new Derived[10];
+
+ d += 1;
+ // no-warning
+
+ delete[] d;
+}
\ No newline at end of file
>From 47068bd748cfb6f1b74b006d0f9918103f936a34 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Mon, 13 May 2024 09:43:46 +0000
Subject: [PATCH 02/15] Display the classname that has the virtual function
Useful for reports within template instantiations.
---
.../bugprone/VirtualArithmeticCheck.cpp | 7 ++++--
.../checkers/bugprone/virtual-arithmetic.cpp | 24 +++++++++++++++----
2 files changed, 24 insertions(+), 7 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
index 57347af2b5881..dec43ae9bd8ca 100644
--- a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
@@ -37,10 +37,13 @@ void VirtualArithmeticCheck::registerMatchers(MatchFinder *Finder) {
void VirtualArithmeticCheck::check(const MatchFinder::MatchResult &Result) {
const auto *PointerExpr = Result.Nodes.getNodeAs<Expr>("pointer");
+ const CXXRecordDecl *PointeeType =
+ PointerExpr->getType()->getPointeeType()->getAsCXXRecordDecl();
diag(PointerExpr->getBeginLoc(),
- "pointer arithmetic on class that declares a virtual function, "
- "undefined behavior if the pointee is a different class");
+ "pointer arithmetic on class '%0' that declares a virtual function, "
+ "undefined behavior if the pointee is a different class")
+ << PointeeType->getName();
}
} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
index d772112293cbc..d89e75186c60f 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
@@ -11,16 +11,16 @@ void operators() {
Base *b = new Derived[10];
b += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
b = b + 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
b++;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
b[1];
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
delete[] static_cast<Derived*>(b);
}
@@ -31,7 +31,7 @@ void subclassWarnings() {
// 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 class that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function
delete[] b;
@@ -42,4 +42,18 @@ void subclassWarnings() {
// no-warning
delete[] d;
+}
+
+template <typename T>
+void templateWarning(T *t) {
+ // FIXME: Show the location of the template instantiation in diagnostic.
+ t += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function
+}
+
+void functionArgument(Base *b) {
+ b += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function
+
+ templateWarning(b);
}
\ No newline at end of file
>From df2e3f1d40b674a8a49b678bf3403a5a4cb5e08b Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Thu, 23 May 2024 11:26:50 +0000
Subject: [PATCH 03/15] Rename check to
`bugprone-pointer-arithmetic-on-polymorphic-object`
---
.../clang-tidy/bugprone/BugproneTidyModule.cpp | 6 +++---
.../clang-tidy/bugprone/CMakeLists.txt | 2 +-
...ointerArithmeticOnPolymorphicObjectCheck.cpp} | 14 ++++++++------
... PointerArithmeticOnPolymorphicObjectCheck.h} | 15 ++++++++-------
...pointer-arithmetic-on-polymorphic-object.rst} | 10 +++++-----
.../docs/clang-tidy/checks/list.rst | 2 +-
...pointer-arithmetic-on-polymorphic-object.cpp} | 16 ++++++++--------
7 files changed, 34 insertions(+), 31 deletions(-)
rename clang-tools-extra/clang-tidy/bugprone/{VirtualArithmeticCheck.cpp => PointerArithmeticOnPolymorphicObjectCheck.cpp} (74%)
rename clang-tools-extra/clang-tidy/bugprone/{VirtualArithmeticCheck.h => PointerArithmeticOnPolymorphicObjectCheck.h} (52%)
rename clang-tools-extra/docs/clang-tidy/checks/bugprone/{virtual-arithmetic.rst => pointer-arithmetic-on-polymorphic-object.rst} (88%)
rename clang-tools-extra/test/clang-tidy/checkers/bugprone/{virtual-arithmetic.cpp => pointer-arithmetic-on-polymorphic-object.cpp} (56%)
diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 813f6720074ae..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"
@@ -91,7 +92,6 @@
#include "UnusedRaiiCheck.h"
#include "UnusedReturnValueCheck.h"
#include "UseAfterMoveCheck.h"
-#include "VirtualArithmeticCheck.h"
#include "VirtualNearMissCheck.h"
namespace clang::tidy {
@@ -172,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>(
@@ -255,8 +257,6 @@ class BugproneModule : public ClangTidyModule {
CheckFactories.registerCheck<UnusedReturnValueCheck>(
"bugprone-unused-return-value");
CheckFactories.registerCheck<UseAfterMoveCheck>("bugprone-use-after-move");
- CheckFactories.registerCheck<VirtualArithmeticCheck>(
- "bugprone-virtual-arithmetic");
CheckFactories.registerCheck<VirtualNearMissCheck>(
"bugprone-virtual-near-miss");
}
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index ec1f3231e7990..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
@@ -87,7 +88,6 @@ add_clang_library(clangTidyBugproneModule
UnusedRaiiCheck.cpp
UnusedReturnValueCheck.cpp
UseAfterMoveCheck.cpp
- VirtualArithmeticCheck.cpp
VirtualNearMissCheck.cpp
LINK_LIBS
diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
similarity index 74%
rename from clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
rename to clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
index dec43ae9bd8ca..918c38b416f66 100644
--- a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
@@ -1,4 +1,4 @@
-//===--- VirtualArithmeticCheck.cpp - clang-tidy---------------------------===//
+//===--- 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.
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "VirtualArithmeticCheck.h"
+#include "PointerArithmeticOnPolymorphicObjectCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
@@ -14,7 +14,8 @@ using namespace clang::ast_matchers;
namespace clang::tidy::bugprone {
-void VirtualArithmeticCheck::registerMatchers(MatchFinder *Finder) {
+void PointerArithmeticOnPolymorphicObjectCheck::registerMatchers(
+ MatchFinder *Finder) {
const auto PointerExprWithVirtualMethod =
expr(hasType(pointerType(pointee(hasDeclaration(
cxxRecordDecl(hasMethod(isVirtualAsWritten())))))))
@@ -35,14 +36,15 @@ void VirtualArithmeticCheck::registerMatchers(MatchFinder *Finder) {
expr(anyOf(ArraySubscript, BinaryOperators, UnaryOperators)), this);
}
-void VirtualArithmeticCheck::check(const MatchFinder::MatchResult &Result) {
+void PointerArithmeticOnPolymorphicObjectCheck::check(
+ const MatchFinder::MatchResult &Result) {
const auto *PointerExpr = Result.Nodes.getNodeAs<Expr>("pointer");
const CXXRecordDecl *PointeeType =
PointerExpr->getType()->getPointeeType()->getAsCXXRecordDecl();
diag(PointerExpr->getBeginLoc(),
- "pointer arithmetic on class '%0' that declares a virtual function, "
- "undefined behavior if the pointee is a different class")
+ "pointer arithmetic on polymorphic class '%0' that declares a virtual "
+ "function, undefined behavior if the pointee is a different class")
<< PointeeType->getName();
}
diff --git a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.h b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
similarity index 52%
rename from clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.h
rename to clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
index 6a5f86a391747..0277d2b53af7b 100644
--- a/clang-tools-extra/clang-tidy/bugprone/VirtualArithmeticCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
@@ -1,4 +1,4 @@
-//===--- VirtualArithmeticCheck.h - clang-tidy-------------------*- C++ -*-===//
+//===--- 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.
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_VIRTUAL_ARITHMETIC_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_VIRTUAL_ARITHMETIC_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_POINTERARITHMETICONPOLYMORPHICOBJECTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_POINTERARITHMETICONPOLYMORPHICOBJECTCHECK_H
#include "../ClangTidyCheck.h"
@@ -16,10 +16,11 @@ namespace clang::tidy::bugprone {
/// Finds pointer arithmetic on classes that declare a virtual function.
///
/// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/virtual-arithmetic.html
-class VirtualArithmeticCheck : public ClangTidyCheck {
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.html
+class PointerArithmeticOnPolymorphicObjectCheck : public ClangTidyCheck {
public:
- VirtualArithmeticCheck(StringRef Name, ClangTidyContext *Context)
+ PointerArithmeticOnPolymorphicObjectCheck(StringRef Name,
+ ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
@@ -27,4 +28,4 @@ class VirtualArithmeticCheck : public ClangTidyCheck {
} // namespace clang::tidy::bugprone
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_VIRTUAL_ARITHMETIC_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_POINTERARITHMETICONPOLYMORPHICOBJECTCHECK_H
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/virtual-arithmetic.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
similarity index 88%
rename from clang-tools-extra/docs/clang-tidy/checks/bugprone/virtual-arithmetic.rst
rename to clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
index 69d43e13392be..a3fa06918bbb3 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/virtual-arithmetic.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object.rst
@@ -1,7 +1,7 @@
-.. title:: clang-tidy - bugprone-virtual-arithmetic
+.. title:: clang-tidy - bugprone-pointer-arithmetic-on-polymorphic-object
-bugprone-virtual-arithmetic
-===========================
+bugprone-pointer-arithmetic-on-polymorphic-object
+=================================================
Warn if pointer arithmetic is performed on a class that declares a
virtual function.
@@ -11,8 +11,6 @@ different from its dynamic type is undefined behavior.
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 class.
-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>`_.
-
Example:
.. code-block:: c++
@@ -48,3 +46,5 @@ as they make up the majority of false positives.
delete[] d;
}
+
+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/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index ba1e5cafa6e47..80e4112a3b780 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -157,7 +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-virtual-arithmetic <bugprone/virtual-arithmetic>`,
+ :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/virtual-arithmetic.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object.cpp
similarity index 56%
rename from clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
rename to clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object.cpp
index d89e75186c60f..c5c92d2ccd9ce 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/virtual-arithmetic.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s bugprone-virtual-arithmetic %t
+// RUN: %check_clang_tidy %s bugprone-pointer-arithmetic-on-polymorphic-object %t
class Base {
public:
@@ -11,16 +11,16 @@ void operators() {
Base *b = new Derived[10];
b += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
b = b + 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
b++;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
b[1];
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-virtual-arithmetic]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
delete[] static_cast<Derived*>(b);
}
@@ -31,7 +31,7 @@ void subclassWarnings() {
// 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 class 'Base' that declares a virtual function
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function
delete[] b;
@@ -48,12 +48,12 @@ template <typename T>
void templateWarning(T *t) {
// FIXME: Show the location of the template instantiation in diagnostic.
t += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function
}
void functionArgument(Base *b) {
b += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on class 'Base' that declares a virtual function
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function
templateWarning(b);
}
\ No newline at end of file
>From fe0d5a7a5f24f75e7eb6e19c69e8d8ea37d7491f Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 03:10:38 +0000
Subject: [PATCH 04/15] Add `MatchInheritedVirtualFunctions` option
---
...nterArithmeticOnPolymorphicObjectCheck.cpp | 39 +++++--
...ointerArithmeticOnPolymorphicObjectCheck.h | 10 +-
clang-tools-extra/docs/ReleaseNotes.rst | 5 +
...inter-arithmetic-on-polymorphic-object.rst | 48 +++++----
...r-arithmetic-on-polymorphic-object-all.cpp | 100 ++++++++++++++++++
...hmetic-on-polymorphic-object-decl-only.cpp | 98 +++++++++++++++++
...inter-arithmetic-on-polymorphic-object.cpp | 59 -----------
7 files changed, 267 insertions(+), 92 deletions(-)
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
delete mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
index 918c38b416f66..6d4fc67a4b79e 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
@@ -14,23 +14,42 @@ using namespace clang::ast_matchers;
namespace clang::tidy::bugprone {
+PointerArithmeticOnPolymorphicObjectCheck::
+ PointerArithmeticOnPolymorphicObjectCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ MatchInheritedVirtualFunctions(
+ Options.get("MatchInheritedVirtualFunctions", false)) {}
+
+void PointerArithmeticOnPolymorphicObjectCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "MatchInheritedVirtualFunctions", true);
+}
+
void PointerArithmeticOnPolymorphicObjectCheck::registerMatchers(
MatchFinder *Finder) {
+ const auto PolymorphicPointerExpr =
+ expr(hasType(pointerType(
+ pointee(hasDeclaration(cxxRecordDecl(hasMethod(isVirtual())))))))
+ .bind("pointer");
+
const auto PointerExprWithVirtualMethod =
- expr(hasType(pointerType(pointee(hasDeclaration(
- cxxRecordDecl(hasMethod(isVirtualAsWritten())))))))
+ expr(hasType(pointerType(pointee(hasDeclaration(cxxRecordDecl(
+ hasMethod(anyOf(isVirtualAsWritten(), isPure()))))))))
.bind("pointer");
- const auto ArraySubscript =
- arraySubscriptExpr(hasBase(PointerExprWithVirtualMethod));
+ const auto SelectedPointerExpr = MatchInheritedVirtualFunctions
+ ? PolymorphicPointerExpr
+ : PointerExprWithVirtualMethod;
+
+ const auto ArraySubscript = arraySubscriptExpr(hasBase(SelectedPointerExpr));
const auto BinaryOperators =
binaryOperator(hasAnyOperatorName("+", "-", "+=", "-="),
- hasEitherOperand(PointerExprWithVirtualMethod));
+ hasEitherOperand(SelectedPointerExpr));
- const auto UnaryOperators =
- unaryOperator(hasAnyOperatorName("++", "--"),
- hasUnaryOperand(PointerExprWithVirtualMethod));
+ const auto UnaryOperators = unaryOperator(
+ hasAnyOperatorName("++", "--"), hasUnaryOperand(SelectedPointerExpr));
Finder->addMatcher(
expr(anyOf(ArraySubscript, BinaryOperators, UnaryOperators)), this);
@@ -43,8 +62,8 @@ void PointerArithmeticOnPolymorphicObjectCheck::check(
PointerExpr->getType()->getPointeeType()->getAsCXXRecordDecl();
diag(PointerExpr->getBeginLoc(),
- "pointer arithmetic on polymorphic class '%0' that declares a virtual "
- "function, undefined behavior if the pointee is a different class")
+ "pointer arithmetic on polymorphic class '%0', "
+ "undefined behavior if the pointee is a different class")
<< PointeeType->getName();
}
diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
index 0277d2b53af7b..0144b840b3429 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
@@ -13,17 +13,21 @@
namespace clang::tidy::bugprone {
-/// Finds pointer arithmetic on classes that declare a virtual function.
+/// Finds pointer arithmetic performed on classes that declare 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)
- : ClangTidyCheck(Name, Context) {}
+ ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const bool MatchInheritedVirtualFunctions;
};
} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index d59da3a61b7b6..cc7038488b228 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -126,6 +126,11 @@ New checks
reference. This may cause use-after-free errors if the caller uses xvalues as
arguments.
+- 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 declare a virtual function.
+
- New :doc:`bugprone-suspicious-stringview-data-usage
<clang-tidy/checks/bugprone/suspicious-stringview-data-usage>` check.
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
index a3fa06918bbb3..ac782d20a043f 100644
--- 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
@@ -3,8 +3,7 @@
bugprone-pointer-arithmetic-on-polymorphic-object
=================================================
-Warn if pointer arithmetic is performed on a class that declares a
-virtual function.
+Finds pointer arithmetic performed on classes that declare a virtual function.
Pointer arithmetic on polymorphic objects where the pointer's static type is
different from its dynamic type is undefined behavior.
@@ -25,26 +24,35 @@ Example:
Base *b = new Derived[10];
b += 1;
- // warning: pointer arithmetic on class that declares a virtual function, undefined behavior if the pointee is a different class
+ // warning: pointer arithmetic on class that declares a virtual function,
+ // undefined behavior if the pointee is a different class
delete[] static_cast<Derived*>(b);
}
-Classes that do not declare a new virtual function are excluded,
-as they make up the majority of false positives.
-
-.. code-block:: c++
-
- void bar() {
- Base *b = new Base[10];
- b += 1; // warning, as Base has a virtual destructor
-
- delete[] b;
-
- Derived *d = new Derived[10];
- d += 1; // no warning, as Derived overrides the destructor
-
- delete[] d;
- }
-
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>`_.
+
+Options
+-------
+
+.. option:: MatchInheritedVirtualFunctions
+
+ When ``true``, all classes with a virtual function are considered,
+ even if the function is inherited.
+ Classes that do not declare a new virtual function are excluded
+ by default, as they make up the majority of false positives.
+
+ .. 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 MatchVirtualDeclarationsOnly is set to true
+
+ delete[] d;
+ }
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..2498c292b0027
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp
@@ -0,0 +1,100 @@
+// RUN: %check_clang_tidy %s bugprone-pointer-arithmetic-on-polymorphic-object %t -- \
+// RUN: -config="{CheckOptions: \
+// RUN: {bugprone-pointer-arithmetic-on-polymorphic-object.MatchInheritedVirtualFunctions: true}}"
+
+class Base {
+public:
+ virtual ~Base() {}
+};
+
+class Derived : 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 class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
+ b = b + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
+ b++;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
+ b[1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [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 class 'Base'
+
+ delete[] b;
+
+ // Common false positive is a class that overrides all parent functions.
+ // Matched due to the check configuration.
+ Derived *d = new Derived[10];
+
+ d += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Derived'
+
+ delete[] d;
+}
+
+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 class 'AbstractBase'
+
+ delete[] static_cast<AbstractOverride*>(ab);
+
+ AbstractInherited *ai = new AbstractOverride[10];
+
+ ai += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'AbstractInherited'
+
+ delete[] static_cast<AbstractOverride*>(ai);
+
+ // Matched due to the check configuration.
+ AbstractOverride *ao = new AbstractOverride[10];
+
+ ao += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'AbstractOverride'
+
+ delete[] ao;
+}
+
+template <typename T>
+void templateWarning(T *t) {
+ // FIXME: Show the location of the template instantiation in diagnostic.
+ t += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+}
+
+void functionArgument(Base *b) {
+ b += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+
+ templateWarning(b);
+}
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..4d5583c31d34e
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object-decl-only.cpp
@@ -0,0 +1,98 @@
+// RUN: %check_clang_tidy %s bugprone-pointer-arithmetic-on-polymorphic-object %t
+
+class Base {
+public:
+ virtual ~Base() {}
+};
+
+class Derived : 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 class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
+ b = b + 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
+ b++;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
+ b[1];
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [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 class '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;
+}
+
+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 class 'AbstractBase'
+
+ delete[] static_cast<AbstractOverride*>(ab);
+
+ AbstractInherited *ai = new AbstractOverride[10];
+
+ // FIXME: Match abstract functions that were not overridden.
+ ai += 1;
+ // no-warning
+
+ 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: Show the location of the template instantiation in diagnostic.
+ t += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+}
+
+void functionArgument(Base *b) {
+ b += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+
+ templateWarning(b);
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object.cpp
deleted file mode 100644
index c5c92d2ccd9ce..0000000000000
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/pointer-arithmetic-on-polymorphic-object.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-// RUN: %check_clang_tidy %s bugprone-pointer-arithmetic-on-polymorphic-object %t
-
-class Base {
-public:
- virtual ~Base() {}
-};
-
-class Derived : public Base {};
-
-void operators() {
- Base *b = new Derived[10];
-
- b += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
-
- b = b + 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
-
- b++;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
-
- b[1];
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function, undefined behavior if the pointee is a different class [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 class 'Base' that declares a virtual function
-
- delete[] b;
-
- // Common false positive is a class that overrides all parent functions.
- Derived *d = new Derived[10];
-
- d += 1;
- // no-warning
-
- delete[] d;
-}
-
-template <typename T>
-void templateWarning(T *t) {
- // FIXME: Show the location of the template instantiation in diagnostic.
- t += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function
-}
-
-void functionArgument(Base *b) {
- b += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base' that declares a virtual function
-
- templateWarning(b);
-}
\ No newline at end of file
>From f37392270da0540da49666cb09aeb971739fd2d8 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 03:11:55 +0000
Subject: [PATCH 05/15] Restrict to C++
---
.../bugprone/PointerArithmeticOnPolymorphicObjectCheck.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
index 0144b840b3429..057691a3d57c7 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
@@ -25,6 +25,9 @@ class PointerArithmeticOnPolymorphicObjectCheck : public ClangTidyCheck {
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;
+ }
private:
const bool MatchInheritedVirtualFunctions;
>From a29c9cdfc1c88aa8778c8acf9b0c7abe8ed7b786 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 03:42:05 +0000
Subject: [PATCH 06/15] Update check message and comments
---
...PointerArithmeticOnPolymorphicObjectCheck.cpp | 2 +-
.../pointer-arithmetic-on-polymorphic-object.rst | 3 ++-
...nter-arithmetic-on-polymorphic-object-all.cpp | 16 +++++++++-------
...rithmetic-on-polymorphic-object-decl-only.cpp | 16 +++++++++-------
4 files changed, 21 insertions(+), 16 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
index 6d4fc67a4b79e..b994cab8c2a3b 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
@@ -62,7 +62,7 @@ void PointerArithmeticOnPolymorphicObjectCheck::check(
PointerExpr->getType()->getPointeeType()->getAsCXXRecordDecl();
diag(PointerExpr->getBeginLoc(),
- "pointer arithmetic on polymorphic class '%0', "
+ "pointer arithmetic on polymorphic class '%0', which can result in "
"undefined behavior if the pointee is a different class")
<< PointeeType->getName();
}
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
index ac782d20a043f..598c14be04021 100644
--- 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
@@ -25,7 +25,8 @@ Example:
b += 1;
// warning: pointer arithmetic on class that declares a virtual function,
- // undefined behavior if the pointee is a different class
+ // which can result in undefined behavior if the pointee is a
+ // different class
delete[] static_cast<Derived*>(b);
}
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
index 2498c292b0027..de731b5b7ead7 100644
--- 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
@@ -15,7 +15,9 @@ class AbstractBase {
virtual ~AbstractBase() {}
};
-class AbstractInherited : public AbstractBase {};
+class AbstractInherited : public AbstractBase {
+ void f() override = 0;
+};
class AbstractOverride : public AbstractInherited {
public:
@@ -26,16 +28,16 @@ void operators() {
Base *b = new Derived[10];
b += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
b = b + 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
b++;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
b[1];
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
delete[] static_cast<Derived*>(b);
}
@@ -51,7 +53,7 @@ void subclassWarnings() {
delete[] b;
// Common false positive is a class that overrides all parent functions.
- // Matched due to the check configuration.
+ // Is a warning because of the check configuration.
Derived *d = new Derived[10];
d += 1;
@@ -76,7 +78,7 @@ void abstractWarnings() {
delete[] static_cast<AbstractOverride*>(ai);
- // Matched due to the check configuration.
+ // Is a warning because of the check configuration.
AbstractOverride *ao = new AbstractOverride[10];
ao += 1;
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
index 4d5583c31d34e..e511d7dc644d8 100644
--- 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
@@ -13,7 +13,10 @@ class AbstractBase {
virtual ~AbstractBase() {}
};
-class AbstractInherited : public AbstractBase {};
+class AbstractInherited : public AbstractBase {
+ // FIXME: Check pure virtual functions transitively, not just explicit delete.
+ void f() override = 0;
+};
class AbstractOverride : public AbstractInherited {
public:
@@ -24,16 +27,16 @@ void operators() {
Base *b = new Derived[10];
b += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
b = b + 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
b++;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
b[1];
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
delete[] static_cast<Derived*>(b);
}
@@ -68,9 +71,8 @@ void abstractWarnings() {
AbstractInherited *ai = new AbstractOverride[10];
- // FIXME: Match abstract functions that were not overridden.
ai += 1;
- // no-warning
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'AbstractInherited'
delete[] static_cast<AbstractOverride*>(ai);
>From 914f349c07b9aff0e5dfc4ba527b6bd8c9294881 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 03:43:10 +0000
Subject: [PATCH 07/15] Add support for type aliases
---
...nterArithmeticOnPolymorphicObjectCheck.cpp | 10 ++++++----
...r-arithmetic-on-polymorphic-object-all.cpp | 20 +++++++++++++++++++
...hmetic-on-polymorphic-object-decl-only.cpp | 20 +++++++++++++++++++
3 files changed, 46 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
index b994cab8c2a3b..16946000e2041 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
@@ -29,13 +29,15 @@ void PointerArithmeticOnPolymorphicObjectCheck::storeOptions(
void PointerArithmeticOnPolymorphicObjectCheck::registerMatchers(
MatchFinder *Finder) {
const auto PolymorphicPointerExpr =
- expr(hasType(pointerType(
- pointee(hasDeclaration(cxxRecordDecl(hasMethod(isVirtual())))))))
+ expr(hasType(hasCanonicalType(
+ pointerType(pointee(hasCanonicalType(hasDeclaration(
+ cxxRecordDecl(cxxRecordDecl(hasMethod(isVirtual()))))))))))
.bind("pointer");
const auto PointerExprWithVirtualMethod =
- expr(hasType(pointerType(pointee(hasDeclaration(cxxRecordDecl(
- hasMethod(anyOf(isVirtualAsWritten(), isPure()))))))))
+ expr(hasType(hasCanonicalType(pointerType(
+ pointee(hasCanonicalType(hasDeclaration(cxxRecordDecl(
+ hasMethod(anyOf(isVirtualAsWritten(), isPure()))))))))))
.bind("pointer");
const auto SelectedPointerExpr = MatchInheritedVirtualFunctions
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
index de731b5b7ead7..bdacf09576c93 100644
--- 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
@@ -100,3 +100,23 @@ void functionArgument(Base *b) {
templateWarning(b);
}
+
+using BaseAlias = Base;
+using DerivedAlias = Derived;
+
+using BasePtr = Base*;
+using DerivedPtr = Derived*;
+
+void typeAliases(BaseAlias *b, DerivedAlias *d, BasePtr bp, DerivedPtr dp) {
+ b += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+
+ d += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Derived'
+
+ bp += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+
+ dp += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Derived'
+}
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
index e511d7dc644d8..a7b3c8a19f05d 100644
--- 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
@@ -98,3 +98,23 @@ void functionArgument(Base *b) {
templateWarning(b);
}
+
+using BaseAlias = Base;
+using DerivedAlias = Derived;
+
+using BasePtr = Base*;
+using DerivedPtr = Derived*;
+
+void typeAliases(BaseAlias *b, DerivedAlias *d, BasePtr bp, DerivedPtr dp) {
+ b += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+
+ d += 1;
+ // no-warning
+
+ bp += 1;
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+
+ dp += 1;
+ // no-warning
+}
>From 801d7ec82550b41fd56ae34966ec5dcfb73112be Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 03:46:47 +0000
Subject: [PATCH 08/15] Add tests for prefix `++`
---
.../bugprone/pointer-arithmetic-on-polymorphic-object-all.cpp | 3 +++
.../pointer-arithmetic-on-polymorphic-object-decl-only.cpp | 3 +++
2 files changed, 6 insertions(+)
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
index bdacf09576c93..5bf96b44b56b9 100644
--- 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
@@ -36,6 +36,9 @@ void operators() {
b++;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ --b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
b[1];
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
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
index a7b3c8a19f05d..3718c622596cc 100644
--- 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
@@ -35,6 +35,9 @@ void operators() {
b++;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ --b;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+
b[1];
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
>From e5dc6b21cd9e810a0446c788518e690b3c5eff51 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 03:57:18 +0000
Subject: [PATCH 09/15] Add comment about the UB's cause
---
.../bugprone/pointer-arithmetic-on-polymorphic-object.rst | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
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
index 598c14be04021..b22676f5284d6 100644
--- 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
@@ -6,7 +6,8 @@ bugprone-pointer-arithmetic-on-polymorphic-object
Finds pointer arithmetic performed on classes that declare a virtual function.
Pointer arithmetic on polymorphic objects where the pointer's static type is
-different from its dynamic type is undefined behavior.
+different from its dynamic type is undefined behavior, as the two types can
+have different sizes.
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 class.
>From dc7e63cb7e462adafde499849633e7bf92829755 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 04:04:25 +0000
Subject: [PATCH 10/15] Exclude final classes
---
...nterArithmeticOnPolymorphicObjectCheck.cpp | 6 ++++--
...r-arithmetic-on-polymorphic-object-all.cpp | 21 ++++++++++++++++++-
...hmetic-on-polymorphic-object-decl-only.cpp | 21 ++++++++++++++++++-
3 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
index 16946000e2041..81cbcfec8d43d 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
@@ -31,13 +31,15 @@ void PointerArithmeticOnPolymorphicObjectCheck::registerMatchers(
const auto PolymorphicPointerExpr =
expr(hasType(hasCanonicalType(
pointerType(pointee(hasCanonicalType(hasDeclaration(
- cxxRecordDecl(cxxRecordDecl(hasMethod(isVirtual()))))))))))
+ cxxRecordDecl(cxxRecordDecl(hasMethod(isVirtual())),
+ unless(isFinal())))))))))
.bind("pointer");
const auto PointerExprWithVirtualMethod =
expr(hasType(hasCanonicalType(pointerType(
pointee(hasCanonicalType(hasDeclaration(cxxRecordDecl(
- hasMethod(anyOf(isVirtualAsWritten(), isPure()))))))))))
+ hasMethod(anyOf(isVirtualAsWritten(), isPure())),
+ unless(isFinal())))))))))
.bind("pointer");
const auto SelectedPointerExpr = MatchInheritedVirtualFunctions
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
index 5bf96b44b56b9..d8213416295ac 100644
--- 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
@@ -9,6 +9,8 @@ class Base {
class Derived : public Base {};
+class FinalDerived final : public Base {};
+
class AbstractBase {
public:
virtual void f() = 0;
@@ -63,6 +65,14 @@ void subclassWarnings() {
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Derived'
delete[] d;
+
+ // Final classes cannot have a dynamic type.
+ FinalDerived *fd = new FinalDerived[10];
+
+ fd += 1;
+ // no-warning
+
+ delete[] fd;
}
void abstractWarnings() {
@@ -106,20 +116,29 @@ void functionArgument(Base *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, BasePtr bp, DerivedPtr dp) {
+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 class 'Base'
d += 1;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Derived'
+ fd += 1;
+ // no-warning
+
bp += 1;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
dp += 1;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class '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
index 3718c622596cc..c6cd9d843c7e9 100644
--- 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
@@ -7,6 +7,8 @@ class Base {
class Derived : public Base {};
+class FinalDerived final : public Base {};
+
class AbstractBase {
public:
virtual void f() = 0;
@@ -61,6 +63,14 @@ void subclassWarnings() {
// no-warning
delete[] d;
+
+ // Final classes cannot have a dynamic type.
+ FinalDerived *fd = new FinalDerived[10];
+
+ fd += 1;
+ // no-warning
+
+ delete[] fd;
}
void abstractWarnings() {
@@ -104,20 +114,29 @@ void functionArgument(Base *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, BasePtr bp, DerivedPtr dp) {
+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 class 'Base'
d += 1;
// no-warning
+ fd += 1;
+ // no-warning
+
bp += 1;
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
dp += 1;
// no-warning
+
+ fdp += 1;
+ // no-warning
}
>From 6415b14afba91e9f0d0e4ce54455fb3c6ecbdde9 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Wed, 29 May 2024 07:22:37 +0000
Subject: [PATCH 11/15] Add CERT alias
---
clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
index b06a903f92b3e..29a73ac89cf01 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"
@@ -237,6 +238,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>(
>From 6a4f75acb0190ff232f009b6f141ce998f48541b Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Mon, 3 Jun 2024 05:46:35 +0000
Subject: [PATCH 12/15] Use `isAbstract` matcher for inherited pure functions
---
.../PointerArithmeticOnPolymorphicObjectCheck.cpp | 12 ++++++++----
.../pointer-arithmetic-on-polymorphic-object-all.cpp | 4 +---
...er-arithmetic-on-polymorphic-object-decl-only.cpp | 5 +----
3 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
index 81cbcfec8d43d..53583a808bba1 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
@@ -14,6 +14,10 @@ using namespace clang::ast_matchers;
namespace clang::tidy::bugprone {
+namespace {
+AST_MATCHER(CXXRecordDecl, isAbstract) { return Node.isAbstract(); }
+} // namespace
+
PointerArithmeticOnPolymorphicObjectCheck::
PointerArithmeticOnPolymorphicObjectCheck(StringRef Name,
ClangTidyContext *Context)
@@ -31,15 +35,15 @@ void PointerArithmeticOnPolymorphicObjectCheck::registerMatchers(
const auto PolymorphicPointerExpr =
expr(hasType(hasCanonicalType(
pointerType(pointee(hasCanonicalType(hasDeclaration(
- cxxRecordDecl(cxxRecordDecl(hasMethod(isVirtual())),
- unless(isFinal())))))))))
+ cxxRecordDecl(unless(isFinal()),
+ cxxRecordDecl(hasMethod(isVirtual()))))))))))
.bind("pointer");
const auto PointerExprWithVirtualMethod =
expr(hasType(hasCanonicalType(pointerType(
pointee(hasCanonicalType(hasDeclaration(cxxRecordDecl(
- hasMethod(anyOf(isVirtualAsWritten(), isPure())),
- unless(isFinal())))))))))
+ unless(isFinal()),
+ anyOf(hasMethod(isVirtualAsWritten()), isAbstract())))))))))
.bind("pointer");
const auto SelectedPointerExpr = MatchInheritedVirtualFunctions
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
index d8213416295ac..d0128b6008185 100644
--- 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
@@ -17,9 +17,7 @@ class AbstractBase {
virtual ~AbstractBase() {}
};
-class AbstractInherited : public AbstractBase {
- void f() override = 0;
-};
+class AbstractInherited : public AbstractBase {};
class AbstractOverride : public AbstractInherited {
public:
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
index c6cd9d843c7e9..f16a8f7cce418 100644
--- 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
@@ -15,10 +15,7 @@ class AbstractBase {
virtual ~AbstractBase() {}
};
-class AbstractInherited : public AbstractBase {
- // FIXME: Check pure virtual functions transitively, not just explicit delete.
- void f() override = 0;
-};
+class AbstractInherited : public AbstractBase {};
class AbstractOverride : public AbstractInherited {
public:
>From d0e5bc2bc8a11a5a0eb610364558fed3a8401500 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Mon, 3 Jun 2024 06:13:33 +0000
Subject: [PATCH 13/15] Pipe source range into diag message
---
.../bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
index 53583a808bba1..03294c3124a54 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
@@ -72,7 +72,7 @@ void PointerArithmeticOnPolymorphicObjectCheck::check(
diag(PointerExpr->getBeginLoc(),
"pointer arithmetic on polymorphic class '%0', which can result in "
"undefined behavior if the pointee is a different class")
- << PointeeType->getName();
+ << PointeeType->getName() << PointeeType->getSourceRange();
}
} // namespace clang::tidy::bugprone
>From 3c2508c2ee5acaf86accba8d19fdb2808ade0217 Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Mon, 3 Jun 2024 06:13:41 +0000
Subject: [PATCH 14/15] Docs fixes
---
.../bugprone/pointer-arithmetic-on-polymorphic-object.rst | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
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
index b22676f5284d6..da340a77a2651 100644
--- 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
@@ -39,10 +39,11 @@ Options
.. option:: MatchInheritedVirtualFunctions
- When ``true``, all classes with a virtual function are considered,
+ When `true`, all classes with a virtual function are considered,
even if the function is inherited.
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++
>From 225804a7b96a13f00ce64c57a3c0320738e0364a Mon Sep 17 00:00:00 2001
From: Viktor <viktor.cseh at ericsson.com>
Date: Tue, 18 Jun 2024 08:03:15 +0000
Subject: [PATCH 15/15] Minor fixes
* Renamed IgnoreInheritedVirtualFunctions
* Documented cert-ctr56-cpp
* IgnoreInheritedVirtualFunctions is now false when using cert-ctr56-cpp
---
...nterArithmeticOnPolymorphicObjectCheck.cpp | 45 ++++++++++---------
...ointerArithmeticOnPolymorphicObjectCheck.h | 2 +-
.../clang-tidy/cert/CERTTidyModule.cpp | 1 +
clang-tools-extra/docs/ReleaseNotes.rst | 5 +++
...inter-arithmetic-on-polymorphic-object.rst | 32 ++++++++-----
.../docs/clang-tidy/checks/cert/ctr56-cpp.rst | 10 +++++
...r-arithmetic-on-polymorphic-object-all.cpp | 34 +++++++-------
...hmetic-on-polymorphic-object-decl-only.cpp | 24 +++++-----
8 files changed, 90 insertions(+), 63 deletions(-)
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/cert/ctr56-cpp.rst
diff --git a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
index 03294c3124a54..fbcdea5befd01 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.cpp
@@ -16,39 +16,42 @@ 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),
- MatchInheritedVirtualFunctions(
- Options.get("MatchInheritedVirtualFunctions", false)) {}
+ IgnoreInheritedVirtualFunctions(
+ Options.get("IgnoreInheritedVirtualFunctions", true)) {}
void PointerArithmeticOnPolymorphicObjectCheck::storeOptions(
ClangTidyOptions::OptionMap &Opts) {
- Options.store(Opts, "MatchInheritedVirtualFunctions", true);
+ Options.store(Opts, "IgnoreInheritedVirtualFunctions",
+ IgnoreInheritedVirtualFunctions);
}
void PointerArithmeticOnPolymorphicObjectCheck::registerMatchers(
MatchFinder *Finder) {
const auto PolymorphicPointerExpr =
- expr(hasType(hasCanonicalType(
- pointerType(pointee(hasCanonicalType(hasDeclaration(
- cxxRecordDecl(unless(isFinal()),
- cxxRecordDecl(hasMethod(isVirtual()))))))))))
+ 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())))))))))
+ expr(hasType(hasCanonicalType(
+ pointerType(pointee(hasCanonicalType(hasDeclaration(
+ cxxRecordDecl(
+ unless(isFinal()),
+ anyOf(hasMethod(isVirtualAsWritten()), isAbstract()))
+ .bind("pointee"))))))))
.bind("pointer");
- const auto SelectedPointerExpr = MatchInheritedVirtualFunctions
- ? PolymorphicPointerExpr
- : PointerExprWithVirtualMethod;
+ const auto SelectedPointerExpr = IgnoreInheritedVirtualFunctions
+ ? PointerExprWithVirtualMethod
+ : PolymorphicPointerExpr;
const auto ArraySubscript = arraySubscriptExpr(hasBase(SelectedPointerExpr));
@@ -59,20 +62,20 @@ void PointerArithmeticOnPolymorphicObjectCheck::registerMatchers(
const auto UnaryOperators = unaryOperator(
hasAnyOperatorName("++", "--"), hasUnaryOperand(SelectedPointerExpr));
- Finder->addMatcher(
- expr(anyOf(ArraySubscript, BinaryOperators, UnaryOperators)), this);
+ 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 CXXRecordDecl *PointeeType =
- PointerExpr->getType()->getPointeeType()->getAsCXXRecordDecl();
+ const auto *PointeeDecl = Result.Nodes.getNodeAs<CXXRecordDecl>("pointee");
diag(PointerExpr->getBeginLoc(),
- "pointer arithmetic on polymorphic class '%0', which can result in "
- "undefined behavior if the pointee is a different class")
- << PointeeType->getName() << PointeeType->getSourceRange();
+ "pointer arithmetic on polymorphic object of type '%0', which can "
+ "result in undefined behavior if the pointee is a different object")
+ << PointeeDecl->getName() << PointeeDecl->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
index 057691a3d57c7..97ba6ad3458e5 100644
--- a/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/PointerArithmeticOnPolymorphicObjectCheck.h
@@ -30,7 +30,7 @@ class PointerArithmeticOnPolymorphicObjectCheck : public ClangTidyCheck {
}
private:
- const bool MatchInheritedVirtualFunctions;
+ const bool IgnoreInheritedVirtualFunctions;
};
} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
index 29a73ac89cf01..06a337d6bbf51 100644
--- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
@@ -329,6 +329,7 @@ class CERTModule : public ClangTidyModule {
ClangTidyOptions Options;
ClangTidyOptions::OptionMap &Opts = Options.CheckOptions;
Opts["cert-dcl16-c.NewSuffixes"] = "L;LL;LU;LLU";
+ Opts["cert-ctr56-cpp.IgnoreInheritedVirtualFunctions"] = "false";
Opts["cert-err33-c.CheckedFunctions"] = CertErr33CCheckedFunctions;
Opts["cert-err33-c.AllowCastToVoid"] = "true";
Opts["cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField"] = "false";
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index cc7038488b228..304dc2aa1ba6e 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -171,6 +171,11 @@ New checks
New check aliases
^^^^^^^^^^^^^^^^^
+- New alias :doc:`cert-ctr56-cpp
+ <clang-tidy/checks/cert/ctr56-cpp>` for
+ :doc:`bugprone-pointer-arithmetic-on-polymorphic-object
+ <clang-tidy/checks/bugprone/pointer-arithmetic-on-polymorphic-object>`.
+
Changes in existing checks
^^^^^^^^^^^^^^^^^^^^^^^^^^
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
index da340a77a2651..5b7adb78f6c54 100644
--- 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
@@ -3,13 +3,16 @@
bugprone-pointer-arithmetic-on-polymorphic-object
=================================================
-Finds pointer arithmetic performed on classes that declare a virtual function.
+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.
-Pointer arithmetic on polymorphic objects where the pointer's static type is
-different from its dynamic type is undefined behavior, as the two types can
-have different sizes.
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 class.
+good heuristic, as the pointer is likely to point to a different,
+derived object.
Example:
@@ -32,18 +35,16 @@ Example:
delete[] static_cast<Derived*>(b);
}
-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>`_.
-
Options
-------
-.. option:: MatchInheritedVirtualFunctions
+.. option:: IgnoreInheritedVirtualFunctions
- When `true`, all classes with a virtual function are considered,
- even if the function is inherited.
+ 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`.
+ Default: `true`.
+ When using the alias `cert-ctr56-cpp`, default: `false`.
.. code-block:: c++
@@ -55,7 +56,14 @@ Options
Derived *d = new Derived[10]; // Derived overrides the destructor, and
// declares no other virtual functions
- d += 1; // warning only if MatchVirtualDeclarationsOnly is set to true
+ 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/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
index d0128b6008185..e37d17585d7f9 100644
--- 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
@@ -1,6 +1,6 @@
// RUN: %check_clang_tidy %s bugprone-pointer-arithmetic-on-polymorphic-object %t -- \
// RUN: -config="{CheckOptions: \
-// RUN: {bugprone-pointer-arithmetic-on-polymorphic-object.MatchInheritedVirtualFunctions: true}}"
+// RUN: {bugprone-pointer-arithmetic-on-polymorphic-object.IgnoreInheritedVirtualFunctions: false}}"
class Base {
public:
@@ -28,19 +28,19 @@ void operators() {
Base *b = new Derived[10];
b += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base', which can result in undefined behavior if the pointee is a different object [bugprone-pointer-arithmetic-on-polymorphic-object]
b = b + 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic object of type 'Base', which can result in undefined behavior if the pointee is a different object [bugprone-pointer-arithmetic-on-polymorphic-object]
b++;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base', which can result in undefined behavior if the pointee is a different object [bugprone-pointer-arithmetic-on-polymorphic-object]
--b;
- // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pointer arithmetic on polymorphic object of type 'Base', which can result in undefined behavior if the pointee is a different object [bugprone-pointer-arithmetic-on-polymorphic-object]
b[1];
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base', which can result in undefined behavior if the pointee is a different object [bugprone-pointer-arithmetic-on-polymorphic-object]
delete[] static_cast<Derived*>(b);
}
@@ -51,7 +51,7 @@ void subclassWarnings() {
// 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 class 'Base'
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base'
delete[] b;
@@ -60,7 +60,7 @@ void subclassWarnings() {
Derived *d = new Derived[10];
d += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Derived'
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Derived'
delete[] d;
@@ -78,14 +78,14 @@ void abstractWarnings() {
AbstractBase *ab = new AbstractOverride[10];
ab += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'AbstractBase'
+ // 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 class 'AbstractInherited'
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'AbstractInherited'
delete[] static_cast<AbstractOverride*>(ai);
@@ -93,7 +93,7 @@ void abstractWarnings() {
AbstractOverride *ao = new AbstractOverride[10];
ao += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'AbstractOverride'
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'AbstractOverride'
delete[] ao;
}
@@ -102,12 +102,12 @@ template <typename T>
void templateWarning(T *t) {
// FIXME: Show the location of the template instantiation in diagnostic.
t += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base'
}
void functionArgument(Base *b) {
b += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base'
templateWarning(b);
}
@@ -123,19 +123,19 @@ 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 class 'Base'
+ // 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 class 'Derived'
+ // 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 class 'Base'
+ // 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 class 'Derived'
+ // 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
index f16a8f7cce418..7e173083360f6 100644
--- 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
@@ -26,19 +26,19 @@ void operators() {
Base *b = new Derived[10];
b += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base', which can result in undefined behavior if the pointee is a different object [bugprone-pointer-arithmetic-on-polymorphic-object]
b = b + 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic on polymorphic object of type 'Base', which can result in undefined behavior if the pointee is a different object [bugprone-pointer-arithmetic-on-polymorphic-object]
b++;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base', which can result in undefined behavior if the pointee is a different object [bugprone-pointer-arithmetic-on-polymorphic-object]
--b;
- // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: pointer arithmetic on polymorphic object of type 'Base', which can result in undefined behavior if the pointee is a different object [bugprone-pointer-arithmetic-on-polymorphic-object]
b[1];
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base', which can result in undefined behavior if the pointee is a different class [bugprone-pointer-arithmetic-on-polymorphic-object]
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base', which can result in undefined behavior if the pointee is a different object [bugprone-pointer-arithmetic-on-polymorphic-object]
delete[] static_cast<Derived*>(b);
}
@@ -49,7 +49,7 @@ void subclassWarnings() {
// 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 class 'Base'
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base'
delete[] b;
@@ -75,14 +75,14 @@ void abstractWarnings() {
AbstractBase *ab = new AbstractOverride[10];
ab += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'AbstractBase'
+ // 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 class 'AbstractInherited'
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'AbstractInherited'
delete[] static_cast<AbstractOverride*>(ai);
@@ -99,12 +99,12 @@ template <typename T>
void templateWarning(T *t) {
// FIXME: Show the location of the template instantiation in diagnostic.
t += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base'
}
void functionArgument(Base *b) {
b += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base'
templateWarning(b);
}
@@ -120,7 +120,7 @@ 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 class 'Base'
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base'
d += 1;
// no-warning
@@ -129,7 +129,7 @@ void typeAliases(BaseAlias *b, DerivedAlias *d, FinalDerivedAlias *fd,
// no-warning
bp += 1;
- // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic class 'Base'
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: pointer arithmetic on polymorphic object of type 'Base'
dp += 1;
// no-warning
More information about the cfe-commits
mailing list