]> granicus.if.org Git - clang/commitdiff
[analyzer] fix inlining's handling of mapping actual to formal arguments and limit...
authorTed Kremenek <kremenek@apple.com>
Thu, 12 Jan 2012 19:25:46 +0000 (19:25 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 12 Jan 2012 19:25:46 +0000 (19:25 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148036 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
include/clang/StaticAnalyzer/Core/PathSensitive/Store.h
lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
lib/StaticAnalyzer/Core/ProgramState.cpp
lib/StaticAnalyzer/Core/RegionStore.cpp
lib/StaticAnalyzer/Core/Store.cpp
test/Analysis/inline.c

index af7845af6c17ca3fde27f75b2e4036c3c0ded0b4..2987116e4f1e3fb3db3d160d5f82e2a02a6b0ef8 100644 (file)
@@ -227,7 +227,8 @@ public:
 
   /// enterStackFrame - Returns the state for entry to the given stack frame,
   ///  preserving the current state.
-  const ProgramState *enterStackFrame(const StackFrameContext *frame) const;
+  const ProgramState *enterStackFrame(const LocationContext *callerCtx,
+                                      const StackFrameContext *calleeCtx) const;
 
   /// Get the lvalue for a variable reference.
   Loc getLValue(const VarDecl *D, const LocationContext *LC) const;
index 20b93461376853fe693b3f79d1956e00957d7fe8..52ea37c4314c3f17f19c3e957f59fd3fce7b9850 100644 (file)
@@ -197,7 +197,8 @@ public:
   /// enterStackFrame - Let the StoreManager to do something when execution
   /// engine is about to execute into a callee.
   virtual StoreRef enterStackFrame(const ProgramState *state,
-                                   const StackFrameContext *frame);
+                                   const LocationContext *callerCtx,
+                                   const StackFrameContext *calleeCtx);
 
   virtual void print(Store store, raw_ostream &Out,
                      const char* nl, const char *sep) = 0;
index 81472fae6c3e13f381274ec7d939a6235e2c53fa..ed58cd4a41238b0e2eb9cf44ec871c83fc72f0e0 100644 (file)
@@ -22,8 +22,8 @@ using namespace ento;
 
 void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
   // Get the entry block in the CFG of the callee.
-  const StackFrameContext *SFC = CE.getCalleeContext();
-  const CFG *CalleeCFG = SFC->getCFG();
+  const StackFrameContext *calleeCtx = CE.getCalleeContext();
+  const CFG *CalleeCFG = calleeCtx->getCFG();
   const CFGBlock *Entry = &(CalleeCFG->getEntry());
   
   // Validate the CFG.
@@ -34,11 +34,13 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
   const CFGBlock *Succ = *(Entry->succ_begin());
   
   // Construct an edge representing the starting location in the callee.
-  BlockEdge Loc(Entry, Succ, SFC);
+  BlockEdge Loc(Entry, Succ, calleeCtx);
 
   // Construct a new state which contains the mapping from actual to
   // formal arguments.
-  const ProgramState *state = Pred->getState()->enterStackFrame(SFC);
+  const LocationContext *callerCtx = Pred->getLocationContext();
+  const ProgramState *state = Pred->getState()->enterStackFrame(callerCtx,
+                                                                calleeCtx);
   
   // Construct a new node and add it to the worklist.
   bool isNew;
@@ -115,6 +117,16 @@ void ExprEngine::processCallExit(ExplodedNode *Pred) {
   }
 }
 
+static unsigned getNumberStackFrames(const LocationContext *LCtx) {
+  unsigned count = 0;
+  while (LCtx) {
+    if (isa<StackFrameContext>(LCtx))
+      ++count;
+    LCtx = LCtx->getParent();
+  }
+  return count;  
+}
+
 bool ExprEngine::InlineCall(ExplodedNodeSet &Dst,
                             const CallExpr *CE, 
                             ExplodedNode *Pred) {
@@ -130,6 +142,11 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst,
       // FIXME: Handle C++.
       break;
     case Stmt::CallExprClass: {
+      // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls).
+      // These heuristics are a WIP.
+      if (getNumberStackFrames(Pred->getLocationContext()) == 5)
+        return false;
+      
       // Construct a new stack frame for the callee.
       AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(FD);
       const StackFrameContext *CallerSFC =
index 86a9ac035787a6550d1d353e3caf4b03e6f579e7..5eb0e06bca5dda154ec6479f78842ce483388fd5 100644 (file)
@@ -180,9 +180,11 @@ const ProgramState *ProgramState::unbindLoc(Loc LV) const {
   return makeWithStore(newStore);
 }
 
-const ProgramState *ProgramState::enterStackFrame(const StackFrameContext *frame) const {
+const ProgramState *
+ProgramState::enterStackFrame(const LocationContext *callerCtx,
+                              const StackFrameContext *calleeCtx) const {
   const StoreRef &new_store =
-    getStateManager().StoreMgr->enterStackFrame(this, frame);
+    getStateManager().StoreMgr->enterStackFrame(this, callerCtx, calleeCtx);
   return makeWithStore(new_store);
 }
 
index d2234150dddd59fc2e8cb682accf8eb4718062d2..5bd7d7267502473307358526ba7402a3774fa587 100644 (file)
@@ -380,7 +380,8 @@ public: // Part of public interface to class.
                               SymbolReaper& SymReaper);
 
   StoreRef enterStackFrame(const ProgramState *state,
-                           const StackFrameContext *frame);
+                           const LocationContext *callerCtx,
+                           const StackFrameContext *calleeCtx);
 
   //===------------------------------------------------------------------===//
   // Region "extents".
@@ -1855,36 +1856,40 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store,
 
 
 StoreRef RegionStoreManager::enterStackFrame(const ProgramState *state,
-                                             const StackFrameContext *frame) {
-  FunctionDecl const *FD = cast<FunctionDecl>(frame->getDecl());
+                                             const LocationContext *callerCtx,
+                                             const StackFrameContext *calleeCtx)
+{
+  FunctionDecl const *FD = cast<FunctionDecl>(calleeCtx->getDecl());
   FunctionDecl::param_const_iterator PI = FD->param_begin(), 
                                      PE = FD->param_end();
   StoreRef store = StoreRef(state->getStore(), *this);
 
-  if (CallExpr const *CE = dyn_cast<CallExpr>(frame->getCallSite())) {
+  if (CallExpr const *CE = dyn_cast<CallExpr>(calleeCtx->getCallSite())) {
     CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
 
     // Copy the arg expression value to the arg variables.  We check that
     // PI != PE because the actual number of arguments may be different than
     // the function declaration.
     for (; AI != AE && PI != PE; ++AI, ++PI) {
-      SVal ArgVal = state->getSVal(*AI, frame);
+      SVal ArgVal = state->getSVal(*AI, callerCtx);
       store = Bind(store.getStore(),
-                   svalBuilder.makeLoc(MRMgr.getVarRegion(*PI, frame)), ArgVal);
+                   svalBuilder.makeLoc(MRMgr.getVarRegion(*PI, calleeCtx)),
+                   ArgVal);
     }
   } else if (const CXXConstructExpr *CE =
-               dyn_cast<CXXConstructExpr>(frame->getCallSite())) {
+               dyn_cast<CXXConstructExpr>(calleeCtx->getCallSite())) {
     CXXConstructExpr::const_arg_iterator AI = CE->arg_begin(),
       AE = CE->arg_end();
 
     // Copy the arg expression value to the arg variables.
     for (; AI != AE; ++AI, ++PI) {
-      SVal ArgVal = state->getSVal(*AI, frame);
+      SVal ArgVal = state->getSVal(*AI, callerCtx);
       store = Bind(store.getStore(),
-                   svalBuilder.makeLoc(MRMgr.getVarRegion(*PI,frame)), ArgVal);
+                   svalBuilder.makeLoc(MRMgr.getVarRegion(*PI, calleeCtx)),
+                   ArgVal);
     }
   } else
-    assert(isa<CXXDestructorDecl>(frame->getDecl()));
+    assert(isa<CXXDestructorDecl>(calleeCtx->getDecl()));
 
   return store;
 }
index 543f87879d4ef8dd3e7ebf5708ce3e23627a2a7e..bbe0a1cfe30006448433f1a6fd289837098fee92 100644 (file)
@@ -23,7 +23,8 @@ StoreManager::StoreManager(ProgramStateManager &stateMgr)
     MRMgr(svalBuilder.getRegionManager()), Ctx(stateMgr.getContext()) {}
 
 StoreRef StoreManager::enterStackFrame(const ProgramState *state,
-                                       const StackFrameContext *frame) {
+                                       const LocationContext *callerCtx,
+                                       const StackFrameContext *calleeCtx) {
   return StoreRef(state->getStore(), *this);
 }
 
index e3c7e838934a152f935258b79201be80d66b99dc..de807fb3aad90d13854f2d684b0bd1833fbfa679 100644 (file)
@@ -28,3 +28,33 @@ void test2_f3() {
   test2_f1(test2_f2()); // expected-warning{{too many arguments in call to 'test2_f1'}}
 }
 
+// Test that inlining works with recursive functions.
+
+unsigned factorial(unsigned x) {
+  if (x <= 1)
+    return 1;
+  return x * factorial(x - 1);
+}
+
+void test_factorial() {
+  if (factorial(3) == 6) {
+    int *p = 0;
+    *p = 0xDEADBEEF;  // expected-warning {{null}}
+  }
+  else {
+    int *p = 0;
+    *p = 0xDEADBEEF; // no-warning
+  }
+}
+
+void test_factorial_2() {
+  unsigned x = factorial(3);
+  if (x == factorial(3)) {
+    int *p = 0;
+    *p = 0xDEADBEEF;  // expected-warning {{null}}
+  }
+  else {
+    int *p = 0;
+    *p = 0xDEADBEEF; // no-warning
+  }
+}