Skip to content

Commit e607360

Browse files
authored
[clang][analyzer] Remove array bounds check from PointerSubChecker (#102580)
At pointer subtraction only pointers are allowed that point into an array (or one after the end), this fact was checker by the checker. This check is now removed because it is a special case of array indexing error that is handled by different checkers (like ArrayBoundsV2).
1 parent 11ba72e commit e607360

File tree

4 files changed

+10
-127
lines changed

4 files changed

+10
-127
lines changed

clang/docs/analyzer/checkers.rst

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2501,7 +2501,11 @@ alpha.core.PointerSub (C)
25012501
Check for pointer subtractions on two pointers pointing to different memory
25022502
chunks. According to the C standard §6.5.6 only subtraction of pointers that
25032503
point into (or one past the end) the same array object is valid (for this
2504-
purpose non-array variables are like arrays of size 1).
2504+
purpose non-array variables are like arrays of size 1). This checker only
2505+
searches for different memory objects at subtraction, but does not check if the
2506+
array index is correct. Furthermore, only cases are reported where
2507+
stack-allocated objects are involved (no warnings on pointers to memory
2508+
allocated by `malloc`).
25052509
25062510
.. code-block:: c
25072511
@@ -2511,11 +2515,6 @@ purpose non-array variables are like arrays of size 1).
25112515
x = &d[4] - &c[1]; // warn: 'c' and 'd' are different arrays
25122516
x = (&a + 1) - &a;
25132517
x = &b - &a; // warn: 'a' and 'b' are different variables
2514-
x = (&a + 2) - &a; // warn: for a variable it is only valid to have a pointer
2515-
// to one past the address of it
2516-
x = &c[10] - &c[0];
2517-
x = &c[11] - &c[0]; // warn: index larger than one past the end
2518-
x = &c[-1] - &c[0]; // warn: negative index
25192518
}
25202519
25212520
struct S {
@@ -2538,9 +2537,6 @@ offsets of members in a structure, using pointer subtractions. This is still
25382537
undefined behavior according to the standard and code like this can be replaced
25392538
with the `offsetof` macro.
25402539
2541-
The checker only reports cases where stack-allocated objects are involved (no
2542-
warnings on pointers to memory allocated by `malloc`).
2543-
25442540
.. _alpha-core-StackAddressAsyncEscape:
25452541
25462542
alpha.core.StackAddressAsyncEscape (C)

clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp

Lines changed: 4 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -31,99 +31,12 @@ class PointerSubChecker
3131
const llvm::StringLiteral Msg_MemRegionDifferent =
3232
"Subtraction of two pointers that do not point into the same array "
3333
"is undefined behavior.";
34-
const llvm::StringLiteral Msg_LargeArrayIndex =
35-
"Using an array index greater than the array size at pointer subtraction "
36-
"is undefined behavior.";
37-
const llvm::StringLiteral Msg_NegativeArrayIndex =
38-
"Using a negative array index at pointer subtraction "
39-
"is undefined behavior.";
40-
const llvm::StringLiteral Msg_BadVarIndex =
41-
"Indexing the address of a variable with other than 1 at this place "
42-
"is undefined behavior.";
43-
44-
/// Check that an array is indexed in the allowed range that is 0 to "one
45-
/// after the end". The "array" can be address of a non-array variable.
46-
/// @param E Expression of the pointer subtraction.
47-
/// @param ElemReg An indexed region in the subtraction expression.
48-
/// @param Reg Region of the other side of the expression.
49-
bool checkArrayBounds(CheckerContext &C, const Expr *E,
50-
const ElementRegion *ElemReg,
51-
const MemRegion *Reg) const;
5234

5335
public:
5436
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
5537
};
5638
}
5739

58-
static bool isArrayVar(const MemRegion *R) {
59-
while (R) {
60-
if (isa<VarRegion>(R))
61-
return true;
62-
if (const auto *ER = dyn_cast<ElementRegion>(R))
63-
R = ER->getSuperRegion();
64-
else
65-
return false;
66-
}
67-
return false;
68-
}
69-
70-
bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E,
71-
const ElementRegion *ElemReg,
72-
const MemRegion *Reg) const {
73-
if (!ElemReg)
74-
return true;
75-
76-
const MemRegion *SuperReg = ElemReg->getSuperRegion();
77-
if (!isArrayVar(SuperReg))
78-
return true;
79-
80-
auto ReportBug = [&](const llvm::StringLiteral &Msg) {
81-
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
82-
auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
83-
R->addRange(E->getSourceRange());
84-
C.emitReport(std::move(R));
85-
}
86-
};
87-
88-
ProgramStateRef State = C.getState();
89-
SValBuilder &SVB = C.getSValBuilder();
90-
91-
if (SuperReg == Reg) {
92-
// Case like `(&x + 1) - &x`. Only 1 or 0 is allowed as index.
93-
if (const llvm::APSInt *I = SVB.getKnownValue(State, ElemReg->getIndex());
94-
I && (!I->isOne() && !I->isZero()))
95-
ReportBug(Msg_BadVarIndex);
96-
return false;
97-
}
98-
99-
DefinedOrUnknownSVal ElemCount =
100-
getDynamicElementCount(State, SuperReg, SVB, ElemReg->getElementType());
101-
auto IndexTooLarge = SVB.evalBinOp(C.getState(), BO_GT, ElemReg->getIndex(),
102-
ElemCount, SVB.getConditionType())
103-
.getAs<DefinedOrUnknownSVal>();
104-
if (IndexTooLarge) {
105-
ProgramStateRef S1, S2;
106-
std::tie(S1, S2) = C.getState()->assume(*IndexTooLarge);
107-
if (S1 && !S2) {
108-
ReportBug(Msg_LargeArrayIndex);
109-
return false;
110-
}
111-
}
112-
auto IndexTooSmall = SVB.evalBinOp(State, BO_LT, ElemReg->getIndex(),
113-
SVB.makeZeroVal(SVB.getArrayIndexType()),
114-
SVB.getConditionType())
115-
.getAs<DefinedOrUnknownSVal>();
116-
if (IndexTooSmall) {
117-
ProgramStateRef S1, S2;
118-
std::tie(S1, S2) = State->assume(*IndexTooSmall);
119-
if (S1 && !S2) {
120-
ReportBug(Msg_NegativeArrayIndex);
121-
return false;
122-
}
123-
}
124-
return true;
125-
}
126-
12740
void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
12841
CheckerContext &C) const {
12942
// When doing pointer subtraction, if the two pointers do not point to the
@@ -151,9 +64,11 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
15164
const auto *ElemLR = dyn_cast<ElementRegion>(LR);
15265
const auto *ElemRR = dyn_cast<ElementRegion>(RR);
15366

154-
if (!checkArrayBounds(C, B->getLHS(), ElemLR, RR))
67+
// Allow cases like "(&x + 1) - &x".
68+
if (ElemLR && ElemLR->getSuperRegion() == RR)
15569
return;
156-
if (!checkArrayBounds(C, B->getRHS(), ElemRR, LR))
70+
// Allow cases like "&x - (&x + 1)".
71+
if (ElemRR && ElemRR->getSuperRegion() == LR)
15772
return;
15873

15974
const ValueDecl *DiffDeclL = nullptr;

clang/test/Analysis/pointer-sub-notes.c

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,5 @@
11
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.PointerSub -analyzer-output=text -verify %s
22

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-
203
void different_1() {
214
int a[3]; // expected-note{{Array at the left-hand side of subtraction}}
225
int b[3]; // expected-note{{Array at the right-hand side of subtraction}}

clang/test/Analysis/pointer-sub.c

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,7 @@ void f1(void) {
99
d = (&x + 1) - &x; // no-warning ('&x' is like a single-element array)
1010
d = &x - (&x + 1); // no-warning
1111
d = (&x + 0) - &x; // no-warning
12-
d = (&x - 1) - &x; // expected-warning{{Indexing the address of a variable with other than 1 at this place is undefined behavior}}
13-
d = (&x + 2) - &x; // expected-warning{{Indexing the address of a variable with other than 1 at this place is undefined behavior}}
14-
15-
d = (z + 9) - z; // no-warning (pointers to same array)
16-
d = (z + 10) - z; // no-warning (pointer to "one after the end")
17-
d = (z + 11) - z; // expected-warning{{Using an array index greater than the array size at pointer subtraction is undefined behavior}}
18-
d = (z - 1) - z; // expected-warning{{Using a negative array index at pointer subtraction is undefined behavior}}
12+
d = (z + 10) - z; // no-warning
1913
}
2014

2115
void f2(void) {
@@ -28,11 +22,6 @@ void f2(void) {
2822
q = &b[3];
2923
d = q - p; // expected-warning{{Subtraction of two pointers that}}
3024

31-
q = a + 10;
32-
d = q - p; // no warning (use of pointer to one after the end is allowed)
33-
q = a + 11;
34-
d = q - a; // expected-warning{{Using an array index greater than the array size at pointer subtraction is undefined behavior}}
35-
3625
d = &a[4] - a; // no-warning
3726
d = &a[2] - p; // no-warning
3827
d = &c - p; // expected-warning{{Subtraction of two pointers that}}

0 commit comments

Comments
 (0)