Skip to content

[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

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>();
Expand Down
32 changes: 25 additions & 7 deletions clang/test/Analysis/pointer-sub.c
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
// 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)
d = (long *)&x - (long *)&x;
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)
Expand All @@ -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
Expand Down Expand Up @@ -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;
}
Loading