]> granicus.if.org Git - clang/commitdiff
When analyzing a C++ method (without a specific caller), assume 'this' is non-null...
authorTed Kremenek <kremenek@apple.com>
Thu, 1 Dec 2011 05:29:42 +0000 (05:29 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 1 Dec 2011 05:29:42 +0000 (05:29 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145575 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Core/ExprEngine.cpp
test/Analysis/misc-ps-region-store.cpp

index a3fd4f80dcca32cae6b5f5c2d1ba89ed51bc11e4..f5d26c964556fc0486f08ca0c711cc22985d916c 100644 (file)
@@ -83,13 +83,13 @@ ExprEngine::~ExprEngine() {
 
 const ProgramState *ExprEngine::getInitialState(const LocationContext *InitLoc) {
   const ProgramState *state = StateMgr.getInitialState(InitLoc);
+  const Decl *D = InitLoc->getDecl();
 
   // Preconditions.
-
   // FIXME: It would be nice if we had a more general mechanism to add
   // such preconditions.  Some day.
   do {
-    const Decl *D = InitLoc->getDecl();
+
     if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
       // Precondition: the first argument of 'main' is an integer guaranteed
       //  to be > 0.
@@ -119,25 +119,42 @@ const ProgramState *ExprEngine::getInitialState(const LocationContext *InitLoc)
 
       if (const ProgramState *newState = state->assume(*Constraint, true))
         state = newState;
-
-      break;
     }
+    break;
+  }
+  while (0);
+
+  if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+    // Precondition: 'self' is always non-null upon entry to an Objective-C
+    // method.
+    const ImplicitParamDecl *SelfD = MD->getSelfDecl();
+    const MemRegion *R = state->getRegion(SelfD, InitLoc);
+    SVal V = state->getSVal(loc::MemRegionVal(R));
+
+    if (const Loc *LV = dyn_cast<Loc>(&V)) {
+      // Assume that the pointer value in 'self' is non-null.
+      state = state->assume(*LV, true);
+      assert(state && "'self' cannot be null");
+    }
+  }
 
-    if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
-      // Precondition: 'self' is always non-null upon entry to an Objective-C
-      // method.
-      const ImplicitParamDecl *SelfD = MD->getSelfDecl();
-      const MemRegion *R = state->getRegion(SelfD, InitLoc);
-      SVal V = state->getSVal(loc::MemRegionVal(R));
-
-      if (const Loc *LV = dyn_cast<Loc>(&V)) {
-        // Assume that the pointer value in 'self' is non-null.
-        state = state->assume(*LV, true);
-        assert(state && "'self' cannot be null");
+  if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+    if (!MD->isStatic()) {
+      // Precondition: 'this' is always non-null upon entry to the
+      // top-level function.  This is our starting assumption for
+      // analyzing an "open" program.
+      const StackFrameContext *SFC = InitLoc->getCurrentStackFrame();
+      if (SFC->getParent() == 0) {
+        loc::MemRegionVal L(getCXXThisRegion(MD, SFC));
+        SVal V = state->getSVal(L);
+        if (const Loc *LV = dyn_cast<Loc>(&V)) {
+          state = state->assume(*LV, true);
+          assert(state && "'this' cannot be null");
+        }
       }
     }
-  } while (0);
-
+  }
+    
   return state;
 }
 
index df90a7562dd9628750a61b381e2d7a9b0fa907ec..111f829cd0ff924f18cfd6b9bbf4a75016924655 100644 (file)
@@ -492,3 +492,17 @@ double PR11450() {
   return NaN;
 }
 
+// Test that 'this' is assumed null upon analyzing the entry to a "top-level"
+// function (i.e., when not analyzing from a specific caller).
+struct TestNullThis {
+  int field;
+  void test();
+};
+
+void TestNullThis::test() {
+  int *p = &field;
+  if (p)
+    return;
+  field = 2; // no-warning
+}
+