diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index ec9fd6c75e0d..d00182a871c1 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -61,7 +61,9 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) { return U->getSubExpr()->IgnoreParenCasts(); } else if (const MemberExpr *ME = dyn_cast(E)) { - if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) { + if (ME->isImplicitAccess()) { + return ME; + } else if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) { return ME->getBase()->IgnoreParenCasts(); } else { // If we have a member expr with a dot, the base must have been @@ -73,9 +75,9 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) { return IvarRef->getBase()->IgnoreParenCasts(); } else if (const ArraySubscriptExpr *AE = dyn_cast(E)) { - return AE->getBase(); + return getDerefExpr(AE->getBase()); } - else if (isDeclRefExprToReference(E)) { + else if (isa(E)) { return E; } break; @@ -974,14 +976,11 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, // This code interacts heavily with this hack; otherwise the value // would not be null at all for most fields, so we'd be unable to track it. if (const auto *Op = dyn_cast(Ex)) - if (Op->getOpcode() == UO_AddrOf && Op->getSubExpr()->isLValue()) { - Ex = Op->getSubExpr()->IgnoreParenCasts(); - while (const auto *ME = dyn_cast(Ex)) { - Ex = ME->getBase()->IgnoreParenCasts(); - } - } + if (Op->getOpcode() == UO_AddrOf && Op->getSubExpr()->isLValue()) + if (const Expr *DerefEx = getDerefExpr(Op->getSubExpr())) + Ex = DerefEx; - if (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex)) + if (Ex && (ExplodedGraph::isInterestingLValueExpr(Ex) || CallEvent::isCallStmt(Ex))) Inner = Ex; } diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index dd7e9dd11781..3000e13d32c6 100644 --- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -1338,6 +1338,9 @@ RegionStoreManager::getSizeInElements(ProgramStateRef state, /// the array). This is called by ExprEngine when evaluating casts /// from arrays to pointers. SVal RegionStoreManager::ArrayToPointer(Loc Array, QualType T) { + if (Array.getAs()) + return Array; + if (!Array.getAs()) return UnknownVal(); diff --git a/clang/test/Analysis/null-deref-offsets.c b/clang/test/Analysis/null-deref-offsets.c index 567c47952b97..988cec4985da 100644 --- a/clang/test/Analysis/null-deref-offsets.c +++ b/clang/test/Analysis/null-deref-offsets.c @@ -7,7 +7,7 @@ struct S { int z[2]; }; -void testOffsets(struct S *s) { +void testOffsets(struct S *s, int coin) { if (s != 0) return; @@ -21,14 +21,17 @@ void testOffsets(struct S *s) { // FIXME: These should ideally be true. clang_analyzer_eval(&(s->y) == 4); // expected-warning{{FALSE}} - clang_analyzer_eval(&(s->z[0]) == 8); // expected-warning{{UNKNOWN}} - clang_analyzer_eval(&(s->z[1]) == 12); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(&(s->z[0]) == 8); // expected-warning{{FALSE}} + clang_analyzer_eval(&(s->z[1]) == 12); // expected-warning{{FALSE}} // FIXME: These should ideally be false. clang_analyzer_eval(&(s->y) == 0); // expected-warning{{TRUE}} - clang_analyzer_eval(&(s->z[0]) == 0); // expected-warning{{UNKNOWN}} - clang_analyzer_eval(&(s->z[1]) == 0); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(&(s->z[0]) == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(&(s->z[1]) == 0); // expected-warning{{TRUE}} - // But this should still be a null dereference. - s->y = 5; // expected-warning{{Access to field 'y' results in a dereference of a null pointer (loaded from variable 's')}} + // But these should still be reported as null dereferences. + 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}} }