-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang][analyzer] Add more notes to PointerSubChecker #102432
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Notes appear at out-of-range array index for index value and array size.
@llvm/pr-subscribers-clang Author: Balázs Kéri (balazske) ChangesNotes appear at out-of-range array index for index value and array size. Full diff: https://github.com/llvm/llvm-project/pull/102432.diff 2 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index b856b0edc61514..1b215cc59c95ae 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -73,31 +73,47 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E,
if (!ElemReg)
return true;
+ ProgramStateRef State = C.getState();
+ SValBuilder &SVB = C.getSValBuilder();
+
const MemRegion *SuperReg = ElemReg->getSuperRegion();
if (!isArrayVar(SuperReg))
return true;
+ DefinedOrUnknownSVal ElemCount =
+ getDynamicElementCount(State, SuperReg, SVB, ElemReg->getElementType());
+
+ const ValueDecl *SuperDecl = nullptr;
+ if (auto *DR = dyn_cast<DeclRegion>(SuperReg))
+ SuperDecl = DR->getDecl();
+ const llvm::APSInt *ElemCountKnown = SVB.getKnownValue(State, ElemCount);
+ const llvm::APSInt *IndexKnown =
+ SVB.getKnownValue(State, ElemReg->getIndex());
auto ReportBug = [&](const llvm::StringLiteral &Msg) {
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
R->addRange(E->getSourceRange());
+ if (SuperDecl && ElemCountKnown && SuperDecl->getType()->isArrayType()) {
+ std::string Msg =
+ llvm::formatv("Array of size {0} declared here", *ElemCountKnown);
+ R->addNote(Msg, {SuperDecl, C.getSourceManager()});
+ }
+ if (IndexKnown) {
+ std::string Msg =
+ llvm::formatv("Memory object indexed with {0}", *IndexKnown);
+ R->addNote(Msg, {E, C.getSourceManager(), C.getLocationContext()});
+ }
C.emitReport(std::move(R));
}
};
- ProgramStateRef State = C.getState();
- SValBuilder &SVB = C.getSValBuilder();
-
if (SuperReg == Reg) {
// Case like `(&x + 1) - &x`. Only 1 or 0 is allowed as index.
- if (const llvm::APSInt *I = SVB.getKnownValue(State, ElemReg->getIndex());
- I && (!I->isOne() && !I->isZero()))
+ if (IndexKnown && (!IndexKnown->isOne() && !IndexKnown->isZero()))
ReportBug(Msg_BadVarIndex);
return false;
}
- DefinedOrUnknownSVal ElemCount =
- getDynamicElementCount(State, SuperReg, SVB, ElemReg->getElementType());
auto IndexTooLarge = SVB.evalBinOp(C.getState(), BO_GT, ElemReg->getIndex(),
ElemCount, SVB.getConditionType())
.getAs<DefinedOrUnknownSVal>();
diff --git a/clang/test/Analysis/pointer-sub.c b/clang/test/Analysis/pointer-sub.c
index 194c8918899525..0ce8fe850ca0fe 100644
--- a/clang/test/Analysis/pointer-sub.c
+++ b/clang/test/Analysis/pointer-sub.c
@@ -1,7 +1,7 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.PointerSub -analyzer-output=text-minimal -verify %s
void f1(void) {
- int x, y, z[10];
+ int x, y, z[10]; // expected-note2{{Array of size 10 declared here}}
int d = &y - &x; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
d = z - &y; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
d = &x - &x; // no-warning (subtraction of any two identical pointers is allowed)
@@ -9,18 +9,23 @@ void f1(void) {
d = (&x + 1) - &x; // no-warning ('&x' is like a single-element array)
d = &x - (&x + 1); // no-warning
d = (&x + 0) - &x; // no-warning
- d = (&x - 1) - &x; // expected-warning{{Indexing the address of a variable with other than 1 at this place is undefined behavior}}
- d = (&x + 2) - &x; // expected-warning{{Indexing the address of a variable with other than 1 at this place is undefined behavior}}
+ d = (&x - 1) - &x; // expected-warning{{Indexing the address of a variable with other than 1 at this place is undefined behavior}} \
+ // expected-note{{Memory object indexed with -1}}
+ d = (&x + 2) - &x; // expected-warning{{Indexing the address of a variable with other than 1 at this place is undefined behavior}} \
+ // expected-note{{Memory object indexed with 2}}
d = (z + 9) - z; // no-warning (pointers to same array)
d = (z + 10) - z; // no-warning (pointer to "one after the end")
- d = (z + 11) - z; // expected-warning{{Using an array index greater than the array size at pointer subtraction is undefined behavior}}
- d = (z - 1) - z; // expected-warning{{Using a negative array index at pointer subtraction is undefined behavior}}
+ d = (z + 11) - z; // expected-warning{{Using an array index greater than the array size at pointer subtraction is undefined behavior}} \
+ // expected-note{{Memory object indexed with 11}}
+ d = (z - 1) - z; // expected-warning{{Using a negative array index at pointer subtraction is undefined behavior}} \
+ // expected-note{{Memory object indexed with -1}}
}
void f2(void) {
int a[10], b[10], c; // expected-note{{Array at the left-hand side of subtraction}} \
- // expected-note2{{Array at the right-hand side of subtraction}}
+ // expected-note2{{Array at the right-hand side of subtraction}} \
+ // expected-note{{Array of size 10 declared here}}
int *p = &a[2];
int *q = &a[8];
int d = q - p; // no-warning (pointers into the same array)
@@ -31,7 +36,8 @@ void f2(void) {
q = a + 10;
d = q - p; // no warning (use of pointer to one after the end is allowed)
q = a + 11;
- d = q - a; // expected-warning{{Using an array index greater than the array size at pointer subtraction is undefined behavior}}
+ d = q - a; // expected-warning{{Using an array index greater than the array size at pointer subtraction is undefined behavior}} \
+ // expected-note{{Memory object indexed with 11}}
d = &a[4] - a; // no-warning
d = &a[2] - p; // no-warning
@@ -154,3 +160,15 @@ int f12() {
init_S2(&s);
return s.p1 - s.p2; // no-warning (pointers are unknown)
}
+
+void f13() {
+ int a[0]; // expected-note2{{Array of size 0 declared here}}
+ int *p1 = a, *p2 = a, *p3 = a;
+ --p1;
+ ++p2;
+ int d1 = a - p1; // expected-warning{{negative array index}} \
+ // expected-note{{Memory object indexed with -1}}
+ int d2 = a - p2; // expected-warning{{array index greater}} \
+ // expected-note{{Memory object indexed with 1}}
+ int d3 = a - p3;
+}
|
@llvm/pr-subscribers-clang-static-analyzer-1 Author: Balázs Kéri (balazske) ChangesNotes appear at out-of-range array index for index value and array size. Full diff: https://github.com/llvm/llvm-project/pull/102432.diff 2 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index b856b0edc61514..1b215cc59c95ae 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -73,31 +73,47 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E,
if (!ElemReg)
return true;
+ ProgramStateRef State = C.getState();
+ SValBuilder &SVB = C.getSValBuilder();
+
const MemRegion *SuperReg = ElemReg->getSuperRegion();
if (!isArrayVar(SuperReg))
return true;
+ DefinedOrUnknownSVal ElemCount =
+ getDynamicElementCount(State, SuperReg, SVB, ElemReg->getElementType());
+
+ const ValueDecl *SuperDecl = nullptr;
+ if (auto *DR = dyn_cast<DeclRegion>(SuperReg))
+ SuperDecl = DR->getDecl();
+ const llvm::APSInt *ElemCountKnown = SVB.getKnownValue(State, ElemCount);
+ const llvm::APSInt *IndexKnown =
+ SVB.getKnownValue(State, ElemReg->getIndex());
auto ReportBug = [&](const llvm::StringLiteral &Msg) {
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
R->addRange(E->getSourceRange());
+ if (SuperDecl && ElemCountKnown && SuperDecl->getType()->isArrayType()) {
+ std::string Msg =
+ llvm::formatv("Array of size {0} declared here", *ElemCountKnown);
+ R->addNote(Msg, {SuperDecl, C.getSourceManager()});
+ }
+ if (IndexKnown) {
+ std::string Msg =
+ llvm::formatv("Memory object indexed with {0}", *IndexKnown);
+ R->addNote(Msg, {E, C.getSourceManager(), C.getLocationContext()});
+ }
C.emitReport(std::move(R));
}
};
- ProgramStateRef State = C.getState();
- SValBuilder &SVB = C.getSValBuilder();
-
if (SuperReg == Reg) {
// Case like `(&x + 1) - &x`. Only 1 or 0 is allowed as index.
- if (const llvm::APSInt *I = SVB.getKnownValue(State, ElemReg->getIndex());
- I && (!I->isOne() && !I->isZero()))
+ if (IndexKnown && (!IndexKnown->isOne() && !IndexKnown->isZero()))
ReportBug(Msg_BadVarIndex);
return false;
}
- DefinedOrUnknownSVal ElemCount =
- getDynamicElementCount(State, SuperReg, SVB, ElemReg->getElementType());
auto IndexTooLarge = SVB.evalBinOp(C.getState(), BO_GT, ElemReg->getIndex(),
ElemCount, SVB.getConditionType())
.getAs<DefinedOrUnknownSVal>();
diff --git a/clang/test/Analysis/pointer-sub.c b/clang/test/Analysis/pointer-sub.c
index 194c8918899525..0ce8fe850ca0fe 100644
--- a/clang/test/Analysis/pointer-sub.c
+++ b/clang/test/Analysis/pointer-sub.c
@@ -1,7 +1,7 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.PointerSub -analyzer-output=text-minimal -verify %s
void f1(void) {
- int x, y, z[10];
+ int x, y, z[10]; // expected-note2{{Array of size 10 declared here}}
int d = &y - &x; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
d = z - &y; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
d = &x - &x; // no-warning (subtraction of any two identical pointers is allowed)
@@ -9,18 +9,23 @@ void f1(void) {
d = (&x + 1) - &x; // no-warning ('&x' is like a single-element array)
d = &x - (&x + 1); // no-warning
d = (&x + 0) - &x; // no-warning
- d = (&x - 1) - &x; // expected-warning{{Indexing the address of a variable with other than 1 at this place is undefined behavior}}
- d = (&x + 2) - &x; // expected-warning{{Indexing the address of a variable with other than 1 at this place is undefined behavior}}
+ d = (&x - 1) - &x; // expected-warning{{Indexing the address of a variable with other than 1 at this place is undefined behavior}} \
+ // expected-note{{Memory object indexed with -1}}
+ d = (&x + 2) - &x; // expected-warning{{Indexing the address of a variable with other than 1 at this place is undefined behavior}} \
+ // expected-note{{Memory object indexed with 2}}
d = (z + 9) - z; // no-warning (pointers to same array)
d = (z + 10) - z; // no-warning (pointer to "one after the end")
- d = (z + 11) - z; // expected-warning{{Using an array index greater than the array size at pointer subtraction is undefined behavior}}
- d = (z - 1) - z; // expected-warning{{Using a negative array index at pointer subtraction is undefined behavior}}
+ d = (z + 11) - z; // expected-warning{{Using an array index greater than the array size at pointer subtraction is undefined behavior}} \
+ // expected-note{{Memory object indexed with 11}}
+ d = (z - 1) - z; // expected-warning{{Using a negative array index at pointer subtraction is undefined behavior}} \
+ // expected-note{{Memory object indexed with -1}}
}
void f2(void) {
int a[10], b[10], c; // expected-note{{Array at the left-hand side of subtraction}} \
- // expected-note2{{Array at the right-hand side of subtraction}}
+ // expected-note2{{Array at the right-hand side of subtraction}} \
+ // expected-note{{Array of size 10 declared here}}
int *p = &a[2];
int *q = &a[8];
int d = q - p; // no-warning (pointers into the same array)
@@ -31,7 +36,8 @@ void f2(void) {
q = a + 10;
d = q - p; // no warning (use of pointer to one after the end is allowed)
q = a + 11;
- d = q - a; // expected-warning{{Using an array index greater than the array size at pointer subtraction is undefined behavior}}
+ d = q - a; // expected-warning{{Using an array index greater than the array size at pointer subtraction is undefined behavior}} \
+ // expected-note{{Memory object indexed with 11}}
d = &a[4] - a; // no-warning
d = &a[2] - p; // no-warning
@@ -154,3 +160,15 @@ int f12() {
init_S2(&s);
return s.p1 - s.p2; // no-warning (pointers are unknown)
}
+
+void f13() {
+ int a[0]; // expected-note2{{Array of size 0 declared here}}
+ int *p1 = a, *p2 = a, *p3 = a;
+ --p1;
+ ++p2;
+ int d1 = a - p1; // expected-warning{{negative array index}} \
+ // expected-note{{Memory object indexed with -1}}
+ int d2 = a - p2; // expected-warning{{array index greater}} \
+ // expected-note{{Memory object indexed with 1}}
+ int d3 = a - p3;
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change LGTM, it makes these reports somewhat easier to understand.
However, note that I'll delete all array bounds checking logic from this checker when I'll bring alpha.security.ArrayBoundV2
out of alpha, because there is no reason to have several checkers that are looking for the same error type. (Also note that the logic in ArrayBoundV2
is more sophisticated and general than the logic of this checker.)
This means that you shouldn't work on improving this part of this checker, because your efforts will be wasted when this is removed.
(EDIT: the checker is named ArrayBoundV2, while I originally accidentally wrote ArrayBoundsV2.)
If the |
Yes,
Yes, I can agree with that, checking out of bounds indexing does not belong to this checker. Feel free to create a different commit which removes this feature instead of tweaking its messages. |
I uploaded now #102580 that removes the entire array bounds checking. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
We should close this when that other PR is accepted and merged. Until then I'm putting a "Request changes" mark on this to prevent an accidental merge.
Notes appear at out-of-range array index for index value and array size.