[cfe-commits] r91613 - in /cfe/trunk: include/clang/Analysis/PathSensitive/GRExprEngine.h lib/Analysis/GRExprEngine.cpp

Ted Kremenek kremenek at apple.com
Thu Dec 17 12:06:29 PST 2009


Author: kremenek
Date: Thu Dec 17 14:06:29 2009
New Revision: 91613

URL: http://llvm.org/viewvc/llvm-project?rev=91613&view=rev
Log:
Convert GRExprEngine::VisitCallExpr() to use a worklist instead of recursion to evaluate the arguments of a CallExpr.  This simplifies the logic and makes it easier to read.  (it also avoids any issues with blowing out the stack if the CallExpr had a ridiculous number of arguments)

Modified:
    cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
    cfe/trunk/lib/Analysis/GRExprEngine.cpp

Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h?rev=91613&r1=91612&r2=91613&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h Thu Dec 17 14:06:29 2009
@@ -266,10 +266,6 @@
   void VisitCall(CallExpr* CE, ExplodedNode* Pred,
                  CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
                  ExplodedNodeSet& Dst);
-  void VisitCallRec(CallExpr* CE, ExplodedNode* Pred,
-                    CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
-                    ExplodedNodeSet& Dst, const FunctionProtoType *,
-                    unsigned ParamIdx = 0);
 
   /// VisitCast - Transfer function logic for all casts (implicit and explicit).
   void VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred,

Modified: cfe/trunk/lib/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngine.cpp?rev=91613&r1=91612&r2=91613&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Thu Dec 17 14:06:29 2009
@@ -1549,94 +1549,112 @@
 // Transfer function: Function calls.
 //===----------------------------------------------------------------------===//
 
+namespace {
+class CallExprWLItem {
+public:
+  CallExpr::arg_iterator I;
+  ExplodedNode *N;
+
+  CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n)
+    : I(i), N(n) {}
+};  
+} // end anonymous namespace
+
 void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
                              CallExpr::arg_iterator AI,
                              CallExpr::arg_iterator AE,
                              ExplodedNodeSet& Dst) {
+
   // Determine the type of function we're calling (if available).
   const FunctionProtoType *Proto = NULL;
   QualType FnType = CE->getCallee()->IgnoreParens()->getType();
   if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
     Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
 
-  VisitCallRec(CE, Pred, AI, AE, Dst, Proto, /*ParamIdx=*/0);
-}
-
-void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred,
-                                CallExpr::arg_iterator AI,
-                                CallExpr::arg_iterator AE,
-                                ExplodedNodeSet& Dst,
-                                const FunctionProtoType *Proto,
-                                unsigned ParamIdx) {
-
-  // Process the arguments.
-  if (AI != AE) {
-    // If the call argument is being bound to a reference parameter,
-    // visit it as an lvalue, not an rvalue.
+  // Create a worklist to process the arguments.
+  llvm::SmallVector<CallExprWLItem, 20> WorkList;
+  WorkList.reserve(AE - AI);
+  WorkList.push_back(CallExprWLItem(AI, Pred));
+  
+  ExplodedNodeSet ArgsEvaluated;
+  
+  while (!WorkList.empty()) {
+    CallExprWLItem Item = WorkList.back();
+    WorkList.pop_back();
+    
+    if (Item.I == AE) {
+      ArgsEvaluated.insert(Item.N);
+      continue;
+    }
+    
+    // Evaluate the argument.
+    ExplodedNodeSet Tmp;
+    const unsigned ParamIdx = Item.I - AI;
+    
     bool VisitAsLvalue = false;
     if (Proto && ParamIdx < Proto->getNumArgs())
       VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
-
-    ExplodedNodeSet DstTmp;
+    
     if (VisitAsLvalue)
-      VisitLValue(*AI, Pred, DstTmp);
+      VisitLValue(*Item.I, Item.N, Tmp);
     else
-      Visit(*AI, Pred, DstTmp);
-    ++AI;
-
-    for (ExplodedNodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI != DE;
-         ++DI)
-      VisitCallRec(CE, *DI, AI, AE, Dst, Proto, ParamIdx + 1);
+      Visit(*Item.I, Item.N, Tmp);
+   
+    // Enqueue evaluating the next argument on the worklist.
+    ++(Item.I);
 
-    return;
+    for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
+      WorkList.push_back(CallExprWLItem(Item.I, *NI));
   }
 
-  // If we reach here we have processed all of the arguments.  Evaluate
-  // the callee expression.
+  // Now process the call itself.  First evaluate the callee.
   ExplodedNodeSet DstTmp;
   Expr* Callee = CE->getCallee()->IgnoreParens();
+  
+  for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(),
+                                 NE=ArgsEvaluated.end();
+       NI != NE; ++NI) {
 
-  { // Enter new scope to make the lifetime of 'DstTmp2' bounded.
     ExplodedNodeSet DstTmp2;
-    Visit(Callee, Pred, DstTmp2);
-
+    Visit(Callee, *NI, DstTmp2);
+    
     // Perform the previsit of the CallExpr, storing the results in DstTmp.
     CheckerVisit(CE, DstTmp, DstTmp2, true);
   }
-
-  // Finally, evaluate the function call.
+  
+  // Finally, evaluate the function call.  We try each of the checkers
+  // to see if the can evaluate the function call.
   ExplodedNodeSet DstTmp3;
   
   for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
        DI != DE; ++DI) {
-
+    
     const GRState* state = GetState(*DI);
     SVal L = state->getSVal(Callee);
-
+    
     // FIXME: Add support for symbolic function calls (calls involving
     //  function pointer values that are symbolic).
     SaveAndRestore<bool> OldSink(Builder->BuildSinks);
     ExplodedNodeSet DstChecker;
-
+    
     // If the callee is processed by a checker, skip the rest logic.
     if (CheckerEvalCall(CE, DstChecker, *DI))
       DstTmp3.insert(DstChecker);
     else {
       for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(),
-            DE_Checker = DstChecker.end();
-            DI_Checker != DE_Checker; ++DI_Checker) {
-
-          // Dispatch to the plug-in transfer function.
+           DE_Checker = DstChecker.end();
+           DI_Checker != DE_Checker; ++DI_Checker) {
+        
+        // Dispatch to the plug-in transfer function.
         unsigned OldSize = DstTmp3.size();
         SaveOr OldHasGen(Builder->HasGeneratedNode);
         Pred = *DI_Checker;
-
+        
         // Dispatch to transfer function logic to handle the call itself.
         // FIXME: Allow us to chain together transfer functions.
-        assert(Builder && "GRStmtNodeBuilder must be defined.");
-    
+        assert(Builder && "GRStmtNodeBuilder must be defined.");        
         getTF().EvalCall(DstTmp3, *this, *Builder, CE, L, Pred);
-
+        
         // Handle the case where no nodes where generated.  Auto-generate that
         // contains the updated state if we aren't generating sinks.
         if (!Builder->BuildSinks && DstTmp3.size() == OldSize &&
@@ -1645,9 +1663,10 @@
       }
     }
   }
-
-  // Perform the post-condition check of the CallExpr.
-  CheckerVisit(CE, Dst, DstTmp3, false);
+  
+  // Finally, perform the post-condition check of the CallExpr and store
+  // the created nodes in 'Dst'.
+  CheckerVisit(CE, Dst, DstTmp3, false);  
 }
 
 //===----------------------------------------------------------------------===//





More information about the cfe-commits mailing list