Skip to content

Commit 5704654

Browse files
balazskeAlexisPerry
authored andcommitted
[clang][analyzer] Add notes to PointerSubChecker (llvm#95899)
Notes are added to indicate the array declarations of the arrays in a found invalid pointer subtraction.
1 parent 8ba67e8 commit 5704654

File tree

4 files changed

+111
-22
lines changed

4 files changed

+111
-22
lines changed

clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ class PointerSubChecker
4343
bool checkArrayBounds(CheckerContext &C, const Expr *E,
4444
const ElementRegion *ElemReg,
4545
const MemRegion *Reg) const;
46-
void reportBug(CheckerContext &C, const Expr *E,
47-
const llvm::StringLiteral &Msg) const;
4846

4947
public:
5048
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
@@ -57,14 +55,22 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E,
5755
if (!ElemReg)
5856
return true;
5957

58+
auto ReportBug = [&](const llvm::StringLiteral &Msg) {
59+
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
60+
auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
61+
R->addRange(E->getSourceRange());
62+
C.emitReport(std::move(R));
63+
}
64+
};
65+
6066
ProgramStateRef State = C.getState();
6167
const MemRegion *SuperReg = ElemReg->getSuperRegion();
6268
SValBuilder &SVB = C.getSValBuilder();
6369

6470
if (SuperReg == Reg) {
6571
if (const llvm::APSInt *I = SVB.getKnownValue(State, ElemReg->getIndex());
6672
I && (!I->isOne() && !I->isZero()))
67-
reportBug(C, E, Msg_BadVarIndex);
73+
ReportBug(Msg_BadVarIndex);
6874
return false;
6975
}
7076

@@ -77,7 +83,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E,
7783
ProgramStateRef S1, S2;
7884
std::tie(S1, S2) = C.getState()->assume(*IndexTooLarge);
7985
if (S1 && !S2) {
80-
reportBug(C, E, Msg_LargeArrayIndex);
86+
ReportBug(Msg_LargeArrayIndex);
8187
return false;
8288
}
8389
}
@@ -89,22 +95,13 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E,
8995
ProgramStateRef S1, S2;
9096
std::tie(S1, S2) = State->assume(*IndexTooSmall);
9197
if (S1 && !S2) {
92-
reportBug(C, E, Msg_NegativeArrayIndex);
98+
ReportBug(Msg_NegativeArrayIndex);
9399
return false;
94100
}
95101
}
96102
return true;
97103
}
98104

99-
void PointerSubChecker::reportBug(CheckerContext &C, const Expr *E,
100-
const llvm::StringLiteral &Msg) const {
101-
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
102-
auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
103-
R->addRange(E->getSourceRange());
104-
C.emitReport(std::move(R));
105-
}
106-
}
107-
108105
void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
109106
CheckerContext &C) const {
110107
// When doing pointer subtraction, if the two pointers do not point to the
@@ -136,6 +133,9 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
136133
if (!checkArrayBounds(C, B->getRHS(), ElemRR, LR))
137134
return;
138135

136+
const ValueDecl *DiffDeclL = nullptr;
137+
const ValueDecl *DiffDeclR = nullptr;
138+
139139
if (ElemLR && ElemRR) {
140140
const MemRegion *SuperLR = ElemLR->getSuperRegion();
141141
const MemRegion *SuperRR = ElemRR->getSuperRegion();
@@ -144,9 +144,30 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
144144
// Allow arithmetic on different symbolic regions.
145145
if (isa<SymbolicRegion>(SuperLR) || isa<SymbolicRegion>(SuperRR))
146146
return;
147+
if (const auto *SuperDLR = dyn_cast<DeclRegion>(SuperLR))
148+
DiffDeclL = SuperDLR->getDecl();
149+
if (const auto *SuperDRR = dyn_cast<DeclRegion>(SuperRR))
150+
DiffDeclR = SuperDRR->getDecl();
147151
}
148152

149-
reportBug(C, B, Msg_MemRegionDifferent);
153+
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
154+
auto R =
155+
std::make_unique<PathSensitiveBugReport>(BT, Msg_MemRegionDifferent, N);
156+
R->addRange(B->getSourceRange());
157+
// The declarations may be identical even if the regions are different:
158+
// struct { int array[10]; } a, b;
159+
// do_something(&a.array[5] - &b.array[5]);
160+
// In this case don't emit notes.
161+
if (DiffDeclL != DiffDeclR) {
162+
if (DiffDeclL)
163+
R->addNote("Array at the left-hand side of subtraction",
164+
{DiffDeclL, C.getSourceManager()});
165+
if (DiffDeclR)
166+
R->addNote("Array at the right-hand side of subtraction",
167+
{DiffDeclR, C.getSourceManager()});
168+
}
169+
C.emitReport(std::move(R));
170+
}
150171
}
151172

152173
void ento::registerPointerSubChecker(CheckerManager &mgr) {

clang/test/Analysis/casts.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ void locAsIntegerCasts(void *p) {
129129
}
130130

131131
void multiDimensionalArrayPointerCasts(void) {
132-
static int x[10][10];
132+
static int x[10][10]; // expected-note2{{Array at the right-hand side of subtraction}}
133133
int *y1 = &(x[3][5]);
134134
char *z = ((char *) y1) + 2;
135135
int *y2 = (int *)(z - 2);
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.PointerSub -analyzer-output=text -verify %s
2+
3+
void negative_1() {
4+
int a[3];
5+
int x = -1;
6+
// FIXME: should indicate that 'x' is -1
7+
int d = &a[x] - &a[0]; // expected-warning{{Using a negative array index at pointer subtraction is undefined behavior}} \
8+
// expected-note{{Using a negative array index at pointer subtraction is undefined behavior}}
9+
}
10+
11+
void negative_2() {
12+
int a[3];
13+
int *p1 = a, *p2 = a;
14+
--p2;
15+
// FIXME: should indicate that 'p2' is negative
16+
int d = p1 - p2; // expected-warning{{Using a negative array index at pointer subtraction is undefined behavior}} \
17+
// expected-note{{Using a negative array index at pointer subtraction is undefined behavior}}
18+
}
19+
20+
void different_1() {
21+
int a[3]; // expected-note{{Array at the left-hand side of subtraction}}
22+
int b[3]; // expected-note{{Array at the right-hand side of subtraction}}
23+
int d = &a[2] - &b[0]; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \
24+
// expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
25+
}
26+
27+
void different_2() {
28+
int a[3]; // expected-note{{Array at the right-hand side of subtraction}}
29+
int b[3]; // expected-note{{Array at the left-hand side of subtraction}}
30+
int *p1 = a + 1;
31+
int *p2 = b;
32+
int d = p2 - p1; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \
33+
// expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
34+
}
35+
36+
int different_3() {
37+
struct {
38+
int array[5];
39+
} a, b;
40+
return &a.array[3] - &b.array[2]; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \
41+
// expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
42+
}
43+
44+
int different_4() {
45+
struct {
46+
int array1[5]; // expected-note{{Array at the left-hand side of subtraction}}
47+
int array2[5]; // expected-note{{Array at the right-hand side of subtraction}}
48+
} a;
49+
return &a.array1[3] - &a.array2[4]; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \
50+
// expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
51+
}
52+
53+
void different_5() {
54+
int d;
55+
static int x[10][10]; // expected-note2{{Array at the left-hand side of subtraction}}
56+
int *y1 = &(x[3][5]);
57+
char *z = ((char *) y1) + 2;
58+
int *y2 = (int *)(z - 2);
59+
int *y3 = ((int *)x) + 35; // This is offset for [3][5].
60+
61+
d = y2 - y1; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \
62+
// expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
63+
d = y3 - y1; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}} \
64+
// expected-note{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
65+
d = y3 - y2;
66+
}

clang/test/Analysis/pointer-sub.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ void f1(void) {
1919
}
2020

2121
void f2(void) {
22-
int a[10], b[10], c;
22+
int a[10], b[10], c; // expected-note{{Array at the left-hand side of subtraction}} \
23+
// expected-note2{{Array at the right-hand side of subtraction}}
2324
int *p = &a[2];
2425
int *q = &a[8];
2526
int d = q - p; // no-warning (pointers into the same array)
@@ -41,7 +42,8 @@ void f2(void) {
4142
}
4243

4344
void f3(void) {
44-
int a[3][4];
45+
int a[3][4]; // expected-note{{Array at the left-hand side of subtraction}} \
46+
// expected-note2{{Array at the right-hand side of subtraction}}
4547
int d;
4648

4749
d = &(a[2]) - &(a[1]);
@@ -74,8 +76,8 @@ void f4(void) {
7476
typedef struct {
7577
int a;
7678
int b;
77-
int c[10];
78-
int d[10];
79+
int c[10]; // expected-note2{{Array at the right-hand side of subtraction}}
80+
int d[10]; // expected-note2{{Array at the left-hand side of subtraction}}
7981
} S;
8082

8183
void f5(void) {
@@ -100,8 +102,8 @@ void f6(void) {
100102
char *a1 = (char *)&l;
101103
int d = a1[3] - l;
102104

103-
long long la1[3];
104-
long long la2[3];
105+
long long la1[3]; // expected-note{{Array at the right-hand side of subtraction}}
106+
long long la2[3]; // expected-note{{Array at the left-hand side of subtraction}}
105107
char *pla1 = (char *)la1;
106108
char *pla2 = (char *)la2;
107109
d = pla1[1] - pla1[0];

0 commit comments

Comments
 (0)