diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -30,11 +30,14 @@ : public Checker< check::Location, check::Bind, EventDispatcher > { + enum DerefKind { NullPointer, UndefinedPointerValue }; + BugType BT_Null{this, "Dereference of null pointer", categories::MemoryError}; BugType BT_Undef{this, "Dereference of undefined pointer value", categories::MemoryError}; - void reportBug(ProgramStateRef State, const Stmt *S, CheckerContext &C) const; + void reportBug(DerefKind K, ProgramStateRef State, const Stmt *S, + CheckerContext &C) const; public: void checkLocation(SVal location, bool isLoad, const Stmt* S, @@ -117,8 +120,21 @@ return false; } -void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, - CheckerContext &C) const { +void DereferenceChecker::reportBug(DerefKind K, ProgramStateRef State, + const Stmt *S, CheckerContext &C) const { + const BugType *BT = nullptr; + llvm::StringRef DerefKindStr; + switch (K) { + case DerefKind::NullPointer: + BT = &BT_Null; + DerefKindStr = " results in a dereference of a null pointer"; + break; + case DerefKind::UndefinedPointerValue: + BT = &BT_Undef; + DerefKindStr = " results in a dereference of an undefined pointer value"; + break; + }; + // Generate an error node. ExplodedNode *N = C.generateErrorNode(State); if (!N) @@ -135,7 +151,7 @@ const ArraySubscriptExpr *AE = cast(S); AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(), N->getLocationContext()); - os << " results in a null pointer dereference"; + os << DerefKindStr; break; } case Stmt::OMPArraySectionExprClass: { @@ -143,11 +159,11 @@ const OMPArraySectionExpr *AE = cast(S); AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), State.get(), N->getLocationContext()); - os << " results in a null pointer dereference"; + os << DerefKindStr; break; } case Stmt::UnaryOperatorClass: { - os << "Dereference of null pointer"; + os << BT->getDescription(); const UnaryOperator *U = cast(S); AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), State.get(), N->getLocationContext(), true); @@ -156,8 +172,8 @@ case Stmt::MemberExprClass: { const MemberExpr *M = cast(S); if (M->isArrow() || isDeclRefExprToReference(M->getBase())) { - os << "Access to field '" << M->getMemberNameInfo() - << "' results in a dereference of a null pointer"; + os << "Access to field '" << M->getMemberNameInfo() << "'" + << DerefKindStr; AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), State.get(), N->getLocationContext(), true); } @@ -165,8 +181,8 @@ } case Stmt::ObjCIvarRefExprClass: { const ObjCIvarRefExpr *IV = cast(S); - os << "Access to instance variable '" << *IV->getDecl() - << "' results in a dereference of a null pointer"; + os << "Access to instance variable '" << *IV->getDecl() << "'" + << DerefKindStr; AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(), State.get(), N->getLocationContext(), true); break; @@ -176,7 +192,7 @@ } auto report = std::make_unique( - BT_Null, buf.empty() ? BT_Null.getDescription() : StringRef(buf), N); + *BT, buf.empty() ? BT->getDescription() : StringRef(buf), N); bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report); @@ -191,12 +207,9 @@ CheckerContext &C) const { // Check for dereference of an undefined value. if (l.isUndef()) { - if (ExplodedNode *N = C.generateErrorNode()) { - auto report = std::make_unique( - BT_Undef, BT_Undef.getDescription(), N); - bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *report); - C.emitReport(std::move(report)); - } + const Expr *DerefExpr = getDereferenceExpr(S); + if (!suppressReport(DerefExpr)) + reportBug(DerefKind::UndefinedPointerValue, C.getState(), DerefExpr, C); return; } @@ -218,7 +231,7 @@ if (!notNullState) { const Expr *expr = getDereferenceExpr(S); if (!suppressReport(expr)) { - reportBug(nullState, expr, C); + reportBug(DerefKind::NullPointer, nullState, expr, C); return; } } @@ -260,7 +273,7 @@ if (!StNonNull) { const Expr *expr = getDereferenceExpr(S, /*IsBind=*/true); if (!suppressReport(expr)) { - reportBug(StNull, expr, C); + reportBug(DerefKind::NullPointer, StNull, expr, C); return; } } diff --git a/clang/test/Analysis/Inputs/expected-plists/null-deref-path-notes.m.plist b/clang/test/Analysis/Inputs/expected-plists/null-deref-path-notes.m.plist --- a/clang/test/Analysis/Inputs/expected-plists/null-deref-path-notes.m.plist +++ b/clang/test/Analysis/Inputs/expected-plists/null-deref-path-notes.m.plist @@ -986,12 +986,12 @@ depth1 extended_message - Array access (via ivar 'p') results in a null pointer dereference + Array access (via ivar 'p') results in a dereference of a null pointer message - Array access (via ivar 'p') results in a null pointer dereference + Array access (via ivar 'p') results in a dereference of a null pointer - descriptionArray access (via ivar 'p') results in a null pointer dereference + descriptionArray access (via ivar 'p') results in a dereference of a null pointer categoryMemory error typeDereference of null pointer check_namecore.NullDereference diff --git a/clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist b/clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist --- a/clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist +++ b/clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist @@ -9738,12 +9738,12 @@ depth0 extended_message - Array access (from variable 'kindC') results in a null pointer dereference + Array access (from variable 'kindC') results in a dereference of a null pointer message - Array access (from variable 'kindC') results in a null pointer dereference + Array access (from variable 'kindC') results in a dereference of a null pointer - descriptionArray access (from variable 'kindC') results in a null pointer dereference + descriptionArray access (from variable 'kindC') results in a dereference of a null pointer categoryMemory error typeDereference of null pointer check_namecore.NullDereference diff --git a/clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist b/clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist --- a/clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist +++ b/clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist @@ -9738,12 +9738,12 @@ depth0 extended_message - Array access (from variable 'kindC') results in a null pointer dereference + Array access (from variable 'kindC') results in a dereference of a null pointer message - Array access (from variable 'kindC') results in a null pointer dereference + Array access (from variable 'kindC') results in a dereference of a null pointer - descriptionArray access (from variable 'kindC') results in a null pointer dereference + descriptionArray access (from variable 'kindC') results in a dereference of a null pointer categoryMemory error typeDereference of null pointer check_namecore.NullDereference diff --git a/clang/test/Analysis/invalid-deref.c b/clang/test/Analysis/invalid-deref.c new file mode 100644 --- /dev/null +++ b/clang/test/Analysis/invalid-deref.c @@ -0,0 +1,32 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s + +typedef unsigned uintptr_t; + +void f1() { + int *p; + *p = 0; // expected-warning{{Dereference of undefined pointer value}} +} + +struct foo_struct { + int x; +}; + +int f2() { + struct foo_struct *p; + + return p->x++; // expected-warning{{Access to field 'x' results in a dereference of an undefined pointer value (loaded from variable 'p')}} +} + +int f3() { + char *x; + int i = 2; + + return x[i + 1]; // expected-warning{{Array access (from variable 'x') results in a dereference of an undefined pointer value}} +} + +int f3_b() { + char *x; + int i = 2; + + return x[i + 1]++; // expected-warning{{Array access (from variable 'x') results in a dereference of an undefined pointer value}} +} diff --git a/clang/test/Analysis/misc-ps-region-store.m b/clang/test/Analysis/misc-ps-region-store.m --- a/clang/test/Analysis/misc-ps-region-store.m +++ b/clang/test/Analysis/misc-ps-region-store.m @@ -1157,7 +1157,7 @@ struct list_pr8141 * pr8141 (void) { struct list_pr8141 *items; - for (;; items = ({ do { } while (0); items->tail; })) // expected-warning{{Dereference of undefined pointer value}} + for (;; items = ({ do { } while (0); items->tail; })) // expected-warning{{dereference of an undefined pointer value}} { } } diff --git a/clang/test/Analysis/null-deref-offsets.c b/clang/test/Analysis/null-deref-offsets.c --- a/clang/test/Analysis/null-deref-offsets.c +++ b/clang/test/Analysis/null-deref-offsets.c @@ -33,5 +33,5 @@ if (coin) s->y = 5; // expected-warning{{Access to field 'y' results in a dereference of a null pointer (loaded from variable 's')}} else - s->z[1] = 6; // expected-warning{{Array access (via field 'z') results in a null pointer dereference}} + s->z[1] = 6; // expected-warning{{Array access (via field 'z') results in a dereference of a null pointer}} } diff --git a/clang/test/Analysis/null-deref-path-notes.c b/clang/test/Analysis/null-deref-path-notes.c --- a/clang/test/Analysis/null-deref-path-notes.c +++ b/clang/test/Analysis/null-deref-path-notes.c @@ -4,8 +4,8 @@ // of the null pointer for path notes. void pr34373() { int *a = 0; // expected-note{{'a' initialized to a null pointer value}} - (a + 0)[0]; // expected-warning{{Array access results in a null pointer dereference}} - // expected-note@-1{{Array access results in a null pointer dereference}} + (a + 0)[0]; // expected-warning{{Array access results in a dereference of a null pointer}} + // expected-note@-1{{Array access results in a dereference of a null pointer}} } typedef __typeof(sizeof(int)) size_t; diff --git a/clang/test/Analysis/null-deref-path-notes.cpp b/clang/test/Analysis/null-deref-path-notes.cpp --- a/clang/test/Analysis/null-deref-path-notes.cpp +++ b/clang/test/Analysis/null-deref-path-notes.cpp @@ -15,8 +15,8 @@ // Properly track the null pointer in the array field back to the default // constructor of 'h'. void c::f(B &g, int &i) { - e(g.d[9], i); // expected-warning{{Array access (via field 'd') results in a null pointer dereference}} - // expected-note@-1{{Array access (via field 'd') results in a null pointer dereference}} + e(g.d[9], i); // expected-warning{{Array access (via field 'd') results in a dereference of a null pointer}} + // expected-note@-1{{Array access (via field 'd') results in a dereference of a null pointer}} B h, a; // expected-note{{Value assigned to 'h.d'}} a.d == __null; // expected-note{{Assuming the condition is true}} a.d != h.d; // expected-note{{Assuming 'a.d' is equal to 'h.d'}} diff --git a/clang/test/Analysis/null-deref-path-notes.m b/clang/test/Analysis/null-deref-path-notes.m --- a/clang/test/Analysis/null-deref-path-notes.m +++ b/clang/test/Analysis/null-deref-path-notes.m @@ -58,8 +58,8 @@ @public int *p; } - (void)useArray { - p[1] = 2; // expected-warning{{Array access (via ivar 'p') results in a null pointer dereference}} - // expected-note@-1{{Array access (via ivar 'p') results in a null pointer dereference}} + p[1] = 2; // expected-warning{{Array access (via ivar 'p') results in a dereference of a null pointer}} + // expected-note@-1{{Array access (via ivar 'p') results in a dereference of a null pointer}} } @end diff --git a/clang/test/Analysis/null-deref-ps.c b/clang/test/Analysis/null-deref-ps.c --- a/clang/test/Analysis/null-deref-ps.c +++ b/clang/test/Analysis/null-deref-ps.c @@ -34,7 +34,7 @@ if (x) return x[i - 1]; - return x[i+1]; // expected-warning{{Array access (from variable 'x') results in a null pointer dereference}} + return x[i+1]; // expected-warning{{Array access (from variable 'x') results in a dereference of a null pointer}} } int f3_b(char* x) { @@ -44,7 +44,7 @@ if (x) return x[i - 1]; - return x[i+1]++; // expected-warning{{Array access (from variable 'x') results in a null pointer dereference}} + return x[i+1]++; // expected-warning{{Array access (from variable 'x') results in a dereference of a null pointer}} } int f4(int *p) { diff --git a/clang/test/Analysis/silence-checkers-and-packages-core-div-by-zero.cpp b/clang/test/Analysis/silence-checkers-and-packages-core-div-by-zero.cpp --- a/clang/test/Analysis/silence-checkers-and-packages-core-div-by-zero.cpp +++ b/clang/test/Analysis/silence-checkers-and-packages-core-div-by-zero.cpp @@ -14,5 +14,5 @@ return; int x = p[0]; - // expected-warning@-1 {{Array access (from variable 'p') results in a null pointer dereference}} + // expected-warning@-1 {{Array access (from variable 'p') results in a dereference of a null pointer}} }