[clang] [clang][analyzer] Add notes to PointerSubChecker (PR #95899)
Balázs Kéri via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 18 07:08:45 PDT 2024
https://github.com/balazske updated https://github.com/llvm/llvm-project/pull/95899
>From 1eb6e7ebde0e97e1cd077dc27ffd3ebd6ed0e93d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.keri at ericsson.com>
Date: Tue, 18 Jun 2024 10:09:24 +0200
Subject: [PATCH 1/2] [clang][analyzer] Add notes to PointerSubChecker
Notes are added to indicate the array declarations of the
arrays in a found invalid pointer subtraction.
---
.../Checkers/PointerSubChecker.cpp | 45 ++++++++++++-------
clang/test/Analysis/pointer-sub-notes.c | 34 ++++++++++++++
2 files changed, 64 insertions(+), 15 deletions(-)
create mode 100644 clang/test/Analysis/pointer-sub-notes.c
diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index b73534136fdf0..a983e66df0818 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -43,8 +43,6 @@ class PointerSubChecker
bool checkArrayBounds(CheckerContext &C, const Expr *E,
const ElementRegion *ElemReg,
const MemRegion *Reg) const;
- void reportBug(CheckerContext &C, const Expr *E,
- const llvm::StringLiteral &Msg) const;
public:
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
@@ -57,6 +55,14 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E,
if (!ElemReg)
return true;
+ auto ReportBug = [&](const llvm::StringLiteral &Msg) {
+ if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+ auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
+ R->addRange(E->getSourceRange());
+ C.emitReport(std::move(R));
+ }
+ };
+
ProgramStateRef State = C.getState();
const MemRegion *SuperReg = ElemReg->getSuperRegion();
SValBuilder &SVB = C.getSValBuilder();
@@ -64,7 +70,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E,
if (SuperReg == Reg) {
if (const llvm::APSInt *I = SVB.getKnownValue(State, ElemReg->getIndex());
I && (!I->isOne() && !I->isZero()))
- reportBug(C, E, Msg_BadVarIndex);
+ ReportBug(Msg_BadVarIndex);
return false;
}
@@ -77,7 +83,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E,
ProgramStateRef S1, S2;
std::tie(S1, S2) = C.getState()->assume(*IndexTooLarge);
if (S1 && !S2) {
- reportBug(C, E, Msg_LargeArrayIndex);
+ ReportBug(Msg_LargeArrayIndex);
return false;
}
}
@@ -89,22 +95,13 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E,
ProgramStateRef S1, S2;
std::tie(S1, S2) = State->assume(*IndexTooSmall);
if (S1 && !S2) {
- reportBug(C, E, Msg_NegativeArrayIndex);
+ ReportBug(Msg_NegativeArrayIndex);
return false;
}
}
return true;
}
-void PointerSubChecker::reportBug(CheckerContext &C, const Expr *E,
- const llvm::StringLiteral &Msg) const {
- if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
- auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
- R->addRange(E->getSourceRange());
- C.emitReport(std::move(R));
- }
-}
-
void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
CheckerContext &C) const {
// When doing pointer subtraction, if the two pointers do not point to the
@@ -136,6 +133,9 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
if (!checkArrayBounds(C, B->getRHS(), ElemRR, LR))
return;
+ const ValueDecl *DiffDeclL = nullptr;
+ const ValueDecl *DiffDeclR = nullptr;
+
if (ElemLR && ElemRR) {
const MemRegion *SuperLR = ElemLR->getSuperRegion();
const MemRegion *SuperRR = ElemRR->getSuperRegion();
@@ -144,9 +144,24 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
// Allow arithmetic on different symbolic regions.
if (isa<SymbolicRegion>(SuperLR) || isa<SymbolicRegion>(SuperRR))
return;
+ if (const auto *SuperDLR = dyn_cast<DeclRegion>(SuperLR))
+ DiffDeclL = SuperDLR->getDecl();
+ if (const auto *SuperDRR = dyn_cast<DeclRegion>(SuperRR))
+ DiffDeclR = SuperDRR->getDecl();
}
- reportBug(C, B, Msg_MemRegionDifferent);
+ if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+ auto R =
+ std::make_unique<PathSensitiveBugReport>(BT, Msg_MemRegionDifferent, N);
+ R->addRange(B->getSourceRange());
+ if (DiffDeclL)
+ R->addNote("Array at the left-hand side of subtraction",
+ {DiffDeclL, C.getSourceManager()});
+ if (DiffDeclR)
+ R->addNote("Array at the right-hand side of subtraction",
+ {DiffDeclR, C.getSourceManager()});
+ C.emitReport(std::move(R));
+ }
}
void ento::registerPointerSubChecker(CheckerManager &mgr) {
diff --git a/clang/test/Analysis/pointer-sub-notes.c b/clang/test/Analysis/pointer-sub-notes.c
new file mode 100644
index 0000000000000..dfdace3a58deb
--- /dev/null
+++ b/clang/test/Analysis/pointer-sub-notes.c
@@ -0,0 +1,34 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.PointerSub -analyzer-output=text -verify %s
+
+void negative_1() {
+ int a[3];
+ int x = -1;
+ // FIXME: should indicate that 'x' is -1
+ int d = &a[x] - &a[0]; // expected-warning{{Using a negative array index at pointer subtraction is undefined behavior}} \
+ // expected-note{{Using a negative array index at pointer subtraction is undefined behavior}}
+}
+
+void negative_2() {
+ int a[3];
+ int *p1 = a, *p2 = a;
+ --p2;
+ // FIXME: should indicate that 'p2' is negative
+ int d = p1 - p2; // expected-warning{{Using a negative array index at pointer subtraction is undefined behavior}} \
+ // expected-note{{Using a negative array index at pointer subtraction is undefined behavior}}
+}
+
+void different_1() {
+ int a[3]; // expected-note{{Array at the left-hand side of subtraction}}
+ int b[3]; // expected-note{{Array at the right-hand side of subtraction}}
+ int d = &a[2] - &b[0]; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \
+ // expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
+}
+
+void different_2() {
+ int a[3]; // expected-note{{Array at the right-hand side of subtraction}}
+ int b[3]; // expected-note{{Array at the left-hand side of subtraction}}
+ int *p1 = a + 1;
+ int *p2 = b;
+ int d = p2 - p1; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \
+ // expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
+}
>From de36da1d01a3dbdfb122f4599d69d482151c246a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <balazs.keri at ericsson.com>
Date: Tue, 18 Jun 2024 15:43:47 +0200
Subject: [PATCH 2/2] check if the notes would appear at same location
---
.../Checkers/PointerSubChecker.cpp | 14 ++++++++------
clang/test/Analysis/pointer-sub-notes.c | 17 +++++++++++++++++
2 files changed, 25 insertions(+), 6 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index a983e66df0818..a29169dd1c277 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -154,12 +154,14 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
auto R =
std::make_unique<PathSensitiveBugReport>(BT, Msg_MemRegionDifferent, N);
R->addRange(B->getSourceRange());
- if (DiffDeclL)
- R->addNote("Array at the left-hand side of subtraction",
- {DiffDeclL, C.getSourceManager()});
- if (DiffDeclR)
- R->addNote("Array at the right-hand side of subtraction",
- {DiffDeclR, C.getSourceManager()});
+ if (DiffDeclL != DiffDeclR) {
+ if (DiffDeclL)
+ R->addNote("Array at the left-hand side of subtraction",
+ {DiffDeclL, C.getSourceManager()});
+ if (DiffDeclR)
+ R->addNote("Array at the right-hand side of subtraction",
+ {DiffDeclR, C.getSourceManager()});
+ }
C.emitReport(std::move(R));
}
}
diff --git a/clang/test/Analysis/pointer-sub-notes.c b/clang/test/Analysis/pointer-sub-notes.c
index dfdace3a58deb..33fc2388df9c6 100644
--- a/clang/test/Analysis/pointer-sub-notes.c
+++ b/clang/test/Analysis/pointer-sub-notes.c
@@ -32,3 +32,20 @@ void different_2() {
int d = p2 - p1; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \
// expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
}
+
+int different_3() {
+ struct {
+ int array[5];
+ } a, b;
+ return &a.array[3] - &b.array[2]; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \
+ // expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
+}
+
+int different_5() {
+ struct {
+ int array1[5]; // expected-note{{Array at the left-hand side of subtraction}}
+ int array2[5]; // expected-note{{Array at the right-hand side of subtraction}}
+ } a;
+ return &a.array1[3] - &a.array2[4]; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \
+ // expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
+}
More information about the cfe-commits
mailing list