]> granicus.if.org Git - clang/commitdiff
[analyzer] Don't crash if we cache out after making a temporary region.
authorJordan Rose <jordan_rose@apple.com>
Thu, 18 Apr 2013 16:33:40 +0000 (16:33 +0000)
committerJordan Rose <jordan_rose@apple.com>
Thu, 18 Apr 2013 16:33:40 +0000 (16:33 +0000)
A C++ overloaded operator may be implemented as an instance method, and
that instance method may be called on an rvalue object, which has no
associated region. The analyzer handles this by creating a temporary region
just for the evaluation of this call; however, it is possible that /by
creating the region/, the analyzer ends up in a previously-explored state.
In this case we don't need to continue along this path.

This doesn't actually show any behavioral change now, but it starts being
used with the next commit and prevents an assertion failure there.

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

lib/StaticAnalyzer/Core/ExprEngine.cpp
test/Analysis/operator-calls.cpp

index 4759b51de7891140a6787f17d1adaef74603e8d7..885a5adeec75ee78137b70e4b3061de93414bce1 100644 (file)
@@ -864,9 +864,13 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
           const LocationContext *LCtx = Pred->getLocationContext();
           ProgramStateRef NewState =
             createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0));
-          if (NewState != State)
+          if (NewState != State) {
             Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/0,
                                      ProgramPoint::PreStmtKind);
+            // Did we cache out?
+            if (!Pred)
+              break;
+          }
         }
       }
       // FALLTHROUGH
index 4f686e55fdfa7fe4e02f917d51c46b96d5f37d8c..7461d75f673b011841d891cb3581a7ba5f3b70ce 100644 (file)
@@ -49,3 +49,39 @@ namespace UserDefinedConversions {
     clang_analyzer_eval(obj); // expected-warning{{TRUE}}
   }
 }
+
+
+namespace RValues {
+  struct SmallOpaque {
+    float x;
+    int operator +() const {
+      return (int)x;
+    }
+  };
+
+  struct LargeOpaque {
+    float x[4];
+    int operator +() const {
+      return (int)x[0];
+    }
+  };
+
+  SmallOpaque getSmallOpaque() {
+    SmallOpaque obj;
+    obj.x = 1.0;
+    return obj;
+  }
+
+  LargeOpaque getLargeOpaque() {
+    LargeOpaque obj = LargeOpaque();
+    obj.x[0] = 1.0;
+    return obj;
+  }
+
+  void test(int coin) {
+    // Force a cache-out when we try to conjure a temporary region for the operator call.
+    // ...then, don't crash.
+    clang_analyzer_eval(+(coin ? getSmallOpaque() : getSmallOpaque())); // expected-warning{{UNKNOWN}}
+    clang_analyzer_eval(+(coin ? getLargeOpaque() : getLargeOpaque())); // expected-warning{{UNKNOWN}}
+  }
+}