[cfe-commits] r160530 - in /cfe/trunk: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h lib/StaticAnalyzer/Core/CheckerManager.cpp lib/StaticAnalyzer/Core/ExprEngineCXX.cpp lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp lib/StaticAnalyzer/Core/ExprEngineObjC.cpp

Anna Zaks ganna at apple.com
Thu Jul 19 16:38:14 PDT 2012


Author: zaks
Date: Thu Jul 19 18:38:13 2012
New Revision: 160530

URL: http://llvm.org/viewvc/llvm-project?rev=160530&view=rev
Log:
[analyzer] Refactor VisitObjCMessage and VisitCallExpr to rely on the
same implementation for call evaluation.

Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
    cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h?rev=160530&r1=160529&r2=160530&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Thu Jul 19 18:38:13 2012
@@ -467,9 +467,17 @@
                  ExplodedNode *Pred, ProgramStateRef St, SVal TargetLV, SVal Val,
                  const ProgramPointTag *tag = 0);
 
+  /// \brief Create a new state in which the call return value is binded to the
+  /// call origin expression.
+  ProgramStateRef bindReturnValue(const CallEvent &Call,
+                                  const LocationContext *LCtx,
+                                  ProgramStateRef State);
+
   void evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
                 const SimpleCall &Call);
-  void defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+
+  /// \bried Default implementation of call evaluation.
+  void defaultEvalCall(NodeBuilder &B, ExplodedNode *Pred,
                        const CallEvent &Call);
 private:
   void evalLoadCommon(ExplodedNodeSet &Dst,
@@ -491,8 +499,7 @@
                     const ProgramPointTag *tag, bool isLoad);
 
   bool shouldInlineDecl(const Decl *D, ExplodedNode *Pred);
-  bool inlineCall(ExplodedNodeSet &Dst, const CallEvent &Call,
-                  ExplodedNode *Pred);
+  bool inlineCall(const CallEvent &Call, ExplodedNode *Pred);
 
   bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC);
 };

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp?rev=160530&r1=160529&r2=160530&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp Thu Jul 19 18:38:13 2012
@@ -568,8 +568,10 @@
     }
     
     // If none of the checkers evaluated the call, ask ExprEngine to handle it.
-    if (!anyEvaluated)
-      Eng.defaultEvalCall(Dst, Pred, Call);
+    if (!anyEvaluated) {
+      NodeBuilder B(Pred, Dst, Eng.getBuilderContext());
+      Eng.defaultEvalCall(B, Pred, Call);
+    }
   }
 }
 

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=160530&r1=160529&r2=160530&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Thu Jul 19 18:38:13 2012
@@ -54,9 +54,10 @@
                                             Call, *this);
 
   ExplodedNodeSet DstInvalidated;
+  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currentBuilderContext);
   for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
        I != E; ++I)
-    defaultEvalCall(DstInvalidated, *I, Call);
+    defaultEvalCall(Bldr, *I, Call);
 
   ExplodedNodeSet DstPostCall;
   getCheckerManager().runCheckersForPostCall(DstPostCall, DstInvalidated,
@@ -77,9 +78,10 @@
                                             Call, *this);
 
   ExplodedNodeSet DstInvalidated;
+  StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currentBuilderContext);
   for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
        I != E; ++I)
-    defaultEvalCall(DstInvalidated, *I, Call);
+    defaultEvalCall(Bldr, *I, Call);
 
   ExplodedNodeSet DstPostCall;
   getCheckerManager().runCheckersForPostCall(Dst, DstInvalidated,

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=160530&r1=160529&r2=160530&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Thu Jul 19 18:38:13 2012
@@ -266,8 +266,7 @@
   return true;
 }
 
-bool ExprEngine::inlineCall(ExplodedNodeSet &Dst,
-                            const CallEvent &Call,
+bool ExprEngine::inlineCall(const CallEvent &Call,
                             ExplodedNode *Pred) {
   if (!getAnalysisManager().shouldInlineCall())
     return false;
@@ -342,16 +341,16 @@
   return true;
 }
 
-static ProgramStateRef getInlineFailedState(ExplodedNode *&N,
+static ProgramStateRef getInlineFailedState(ProgramStateRef State,
                                             const Stmt *CallE) {
-  void *ReplayState = N->getState()->get<ReplayWithoutInlining>();
+  void *ReplayState = State->get<ReplayWithoutInlining>();
   if (!ReplayState)
     return 0;
 
   assert(ReplayState == (const void*)CallE && "Backtracked to the wrong call.");
   (void)CallE;
 
-  return N->getState()->remove<ReplayWithoutInlining>();
+  return State->remove<ReplayWithoutInlining>();
 }
 
 void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
@@ -419,38 +418,69 @@
                                              Call, *this);
 }
 
-void ExprEngine::defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
+                                            const LocationContext *LCtx,
+                                            ProgramStateRef State) {
+  const Expr *E = Call.getOriginExpr();
+  if (!E)
+    return State;
+
+  // Some method families have known return values.
+  if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) {
+    switch (Msg->getMethodFamily()) {
+    default:
+      break;
+    case OMF_autorelease:
+    case OMF_retain:
+    case OMF_self: {
+      // These methods return their receivers.
+      return State->BindExpr(E, LCtx, Msg->getReceiverSVal());
+      break;
+    }
+    }
+  }
+
+  // Conjure a symbol if the return value is unknown.
+  QualType ResultTy = Call.getResultType();
+  SValBuilder &SVB = getSValBuilder();
+  unsigned Count = currentBuilderContext->getCurrentBlockCount();
+  SVal R = SVB.getConjuredSymbolVal(0, E, LCtx, ResultTy, Count);
+  return State->BindExpr(E, LCtx, R);
+}
+
+void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred,
                                  const CallEvent &Call) {
+  ProgramStateRef State = 0;
+  const Expr *E = Call.getOriginExpr();
+
   // Try to inline the call.
   // The origin expression here is just used as a kind of checksum;
   // for CallEvents that do not have origin expressions, this should still be
   // safe.
-  const Expr *E = Call.getOriginExpr();
-  ProgramStateRef state = getInlineFailedState(Pred, E);
-  if (state == 0 && inlineCall(Dst, Call, Pred))
-    return;
+  if (!isa<ObjCMethodCall>(Call)) {
+    State = getInlineFailedState(Pred->getState(), E);
+    if (State == 0 && inlineCall(Call, Pred)) {
+      // If we inlined the call, the successor has been manually added onto
+      // the work list and we should not consider it for subsequent call
+      // handling steps.
+      Bldr.takeNodes(Pred);
+      return;
+    }
+  }
 
   // If we can't inline it, handle the return value and invalidate the regions.
-  NodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+  if (State == 0)
+    State = Pred->getState();
 
   // Invalidate any regions touched by the call.
   unsigned Count = currentBuilderContext->getCurrentBlockCount();
-  if (state == 0)
-    state = Pred->getState();
-  state = Call.invalidateRegions(Count, state);
-
-  // Conjure a symbol value to use as the result.
-  if (E) {
-    QualType ResultTy = Call.getResultType();
-    SValBuilder &SVB = getSValBuilder();
-    const LocationContext *LCtx = Pred->getLocationContext();
-    SVal RetVal = SVB.getConjuredSymbolVal(0, E, LCtx, ResultTy, Count);
+  State = Call.invalidateRegions(Count, State);
 
-    state = state->BindExpr(E, LCtx, RetVal);
-  }
+  // Construct and bind the return value.
+  State = bindReturnValue(Call, Pred->getLocationContext(), State);
 
   // And make the result node.
-  Bldr.generateNode(Call.getProgramPoint(), state, Pred);
+  Bldr.generateNode(Call.getProgramPoint(), State, Pred);
 }
 
 void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp?rev=160530&r1=160529&r2=160530&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp Thu Jul 19 18:38:13 2012
@@ -158,9 +158,7 @@
 
   for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
        DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
-    
     ExplodedNode *Pred = *DI;
-    bool RaisesException = false;
     
     if (msg.isInstanceMessage()) {
       SVal recVal = msg.getReceiverSVal();
@@ -182,13 +180,19 @@
         
         // Check if the "raise" message was sent.
         assert(notNilState);
-        if (msg.getSelector() == RaiseSel)
-          RaisesException = true;
+        if (msg.getSelector() == RaiseSel) {
+          // If we raise an exception, for now treat it as a sink.
+          // Eventually we will want to handle exceptions properly.
+          Bldr.generateNode(currentStmt, Pred, Pred->getState(), true);
+          continue;
+        }
         
-        // If we raise an exception, for now treat it as a sink.
-        // Eventually we will want to handle exceptions properly.
-        // Dispatch to plug-in transfer function.
-        evalObjCMessage(Bldr, msg, Pred, notNilState, RaisesException);
+        // Generate a transition to non-Nil state.
+        if (notNilState != state)
+          Pred = Bldr.generateNode(currentStmt, Pred, notNilState);
+
+        // Evaluate the call.
+        defaultEvalCall(Bldr, Pred, msg);
       }
     } else {
       // Check for special class methods.
@@ -222,19 +226,25 @@
           }
           
           Selector S = msg.getSelector();
+          bool RaisesException = false;
           for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
             if (S == NSExceptionInstanceRaiseSelectors[i]) {
               RaisesException = true;
               break;
             }
           }
+          if (RaisesException) {
+            // If we raise an exception, for now treat it as a sink.
+            // Eventually we will want to handle exceptions properly.
+            Bldr.generateNode(currentStmt, Pred, Pred->getState(), true);
+            continue;
+          }
+
         }
       }
 
-      // If we raise an exception, for now treat it as a sink.
-      // Eventually we will want to handle exceptions properly.
-      // Dispatch to plug-in transfer function.
-      evalObjCMessage(Bldr, msg, Pred, Pred->getState(), RaisesException);
+      // Evaluate the call.
+      defaultEvalCall(Bldr, Pred, msg);
     }
   }
   
@@ -246,48 +256,3 @@
   getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit,
                                                     msg, *this);
 }
-
-void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
-                                 const ObjCMethodCall &msg,
-                                 ExplodedNode *Pred,
-                                 ProgramStateRef state,
-                                 bool GenSink) {
-  // First handle the return value.
-  SVal ReturnValue = UnknownVal();
-
-  // Some method families have known return values.
-  switch (msg.getMethodFamily()) {
-  default:
-    break;
-  case OMF_autorelease:
-  case OMF_retain:
-  case OMF_self: {
-    // These methods return their receivers.
-    ReturnValue = msg.getReceiverSVal();
-    break;
-  }
-  }
-
-  const LocationContext *LCtx = Pred->getLocationContext();
-  unsigned BlockCount = currentBuilderContext->getCurrentBlockCount();
-
-  // If we failed to figure out the return value, use a conjured value instead.
-  if (ReturnValue.isUnknown()) {
-    SValBuilder &SVB = getSValBuilder();
-    QualType ResultTy = msg.getResultType();
-    const Expr *CurrentE = cast<Expr>(currentStmt);
-    ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, LCtx, ResultTy,
-                                           BlockCount);
-  }
-
-  // Bind the return value.
-  state = state->BindExpr(currentStmt, LCtx, ReturnValue);
-
-  // Invalidate the arguments (and the receiver)
-  state = msg.invalidateRegions(BlockCount, state);
-
-  // And create the new node.
-  Bldr.generateNode(currentStmt, Pred, state, GenSink);
-  assert(Bldr.hasGeneratedNodes());
-}
-





More information about the cfe-commits mailing list