]> granicus.if.org Git - clang/commitdiff
[analyzer] PR43102: Fix an assertion and an out-of-bounds error for diagnostic locati...
authorKristof Umann <kristof.umann@ericsson.com>
Wed, 18 Sep 2019 22:24:26 +0000 (22:24 +0000)
committerKristof Umann <kristof.umann@ericsson.com>
Wed, 18 Sep 2019 22:24:26 +0000 (22:24 +0000)
Summary:
https://bugs.llvm.org/show_bug.cgi?id=43102

In today's edition of "Is this any better now that it isn't crashing?", I'd like to show you a very interesting test case with loop widening.

Looking at the included test case, it's immediately obvious that this is not only a false positive, but also a very bad bug report in general. We can see how the analyzer mistakenly invalidated `b`, instead of its pointee, resulting in it reporting a null pointer dereference error. Not only that, the point at which this change of value is noted at is at the loop, rather then at the method call.

It turns out that `FindLastStoreVisitor` works correctly, rather the supplied explodedgraph is faulty, because `BlockEdge` really is the `ProgramPoint` where this happens.
{F9855739}
So it's fair to say that this needs improving on multiple fronts. In any case, at least the crash is gone.

Full ExplodedGraph: {F9855743}

Reviewers: NoQ, xazax.hun, baloghadamsoftware, Charusso, dcoughlin, rnkovacs, TWeaver

Subscribers: JesperAntonsson, uabelho, Ka-Ka, bjope, whisperity, szepet, a.sidorin, mikhail.ramalho, donat.nagy, dkrupp, gamesh411, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D66716

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@372269 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/PathDiagnostic.cpp
lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
test/Analysis/loop-widening.cpp [new file with mode: 0644]

index 764cb8ed0e4f87100d0d0954a6ec736e02b93963..53235ba076994606f8847bef48b713936f916dbe 100644 (file)
@@ -695,14 +695,18 @@ PathDiagnosticLocation::create(const ProgramPoint& P,
     return PathDiagnosticLocation(
         CEB->getLocationContext()->getDecl()->getSourceRange().getEnd(), SMng);
   } else if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
-    CFGElement BlockFront = BE->getBlock()->front();
-    if (auto StmtElt = BlockFront.getAs<CFGStmt>()) {
-      return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng);
-    } else if (auto NewAllocElt = BlockFront.getAs<CFGNewAllocator>()) {
-      return PathDiagnosticLocation(
-          NewAllocElt->getAllocatorExpr()->getBeginLoc(), SMng);
+    if (Optional<CFGElement> BlockFront = BE->getFirstElement()) {
+      if (auto StmtElt = BlockFront->getAs<CFGStmt>()) {
+        return PathDiagnosticLocation(StmtElt->getStmt()->getBeginLoc(), SMng);
+      } else if (auto NewAllocElt = BlockFront->getAs<CFGNewAllocator>()) {
+        return PathDiagnosticLocation(
+            NewAllocElt->getAllocatorExpr()->getBeginLoc(), SMng);
+      }
+      llvm_unreachable("Unexpected CFG element at front of block");
     }
-    llvm_unreachable("Unexpected CFG element at front of block");
+
+    return PathDiagnosticLocation(
+        BE->getBlock()->getTerminatorStmt()->getBeginLoc(), SMng);
   } else if (Optional<FunctionExitPoint> FE = P.getAs<FunctionExitPoint>()) {
     return PathDiagnosticLocation(FE->getStmt(), SMng,
                                   FE->getLocationContext());
index c6b7ef041ac4e36b5e703656587e290c2e804d16..f1592ebff669dbbd5b948250497f4897bc4e3f31 100644 (file)
@@ -1438,6 +1438,7 @@ FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
 
   if (!StoreSite)
     return nullptr;
+
   Satisfied = true;
 
   // If we have an expression that provided the value, try to track where it
@@ -1802,7 +1803,7 @@ TrackControlDependencyCondBRVisitor::VisitNode(const ExplodedNode *N,
   if (ControlDeps.isControlDependent(OriginB, NB)) {
     // We don't really want to explain for range loops. Evidence suggests that
     // the only thing that leads to is the addition of calls to operator!=.
-    if (isa<CXXForRangeStmt>(NB->getTerminator()))
+    if (llvm::isa_and_nonnull<CXXForRangeStmt>(NB->getTerminatorStmt()))
       return nullptr;
 
     if (const Expr *Condition = NB->getLastCondition()) {
diff --git a/test/Analysis/loop-widening.cpp b/test/Analysis/loop-widening.cpp
new file mode 100644 (file)
index 0000000..fbcb72d
--- /dev/null
@@ -0,0 +1,27 @@
+// RUN: %clang_analyze_cc1 -verify %s \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config widen-loops=true \
+// RUN:   -analyzer-config track-conditions=false \
+// RUN:   -analyzer-max-loop 2 -analyzer-output=text
+
+namespace pr43102 {
+class A {
+public:
+  void m_fn1();
+};
+bool g;
+void fn1() {
+  A a;
+  A *b = &a;
+
+  for (;;) { // expected-note{{Loop condition is true.  Entering loop body}}
+             // expected-note@-1{{Loop condition is true.  Entering loop body}}
+             // expected-note@-2{{Value assigned to 'b'}}
+             // no crash during bug report construction
+
+    g = !b;     // expected-note{{Assuming 'b' is null}}
+    b->m_fn1(); // expected-warning{{Called C++ object pointer is null}}
+                // expected-note@-1{{Called C++ object pointer is null}}
+  }
+}
+} // end of namespace pr43102