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

Jordan Rose jordan_rose at apple.com
Mon Jul 2 12:28:10 PDT 2012


Author: jrose
Date: Mon Jul  2 14:28:09 2012
New Revision: 159560

URL: http://llvm.org/viewvc/llvm-project?rev=159560&view=rev
Log:
[analyzer] Use CallEvent for inlining and call default-evaluation.

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

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h?rev=159560&r1=159559&r2=159560&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/CheckerManager.h Mon Jul  2 14:28:09 2012
@@ -33,6 +33,7 @@
   class AnalysisManager;
   class BugReporter;
   class CheckerContext;
+  class SimpleCall;
   class ObjCMethodCall;
   class SVal;
   class ExplodedNode;
@@ -44,12 +45,6 @@
   class MemRegion;
   class SymbolReaper;
 
-class GraphExpander {
-public:
-  virtual ~GraphExpander();
-  virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) = 0;
-};
-
 template <typename T> class CheckerFn;
 
 template <typename RET, typename P1, typename P2, typename P3, typename P4,
@@ -303,8 +298,7 @@
   /// \brief Run checkers for evaluating a call.
   void runCheckersForEvalCall(ExplodedNodeSet &Dst,
                               const ExplodedNodeSet &Src,
-                              const CallExpr *CE, ExprEngine &Eng,
-                              GraphExpander *defaultEval = 0);
+                              const SimpleCall &CE, ExprEngine &Eng);
   
   /// \brief Run checkers for the entire Translation Unit.
   void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU,

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h?rev=159560&r1=159559&r2=159560&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h Mon Jul  2 14:28:09 2012
@@ -278,16 +278,27 @@
 public:
   BlockCall(const CallExpr *CE, ProgramStateRef St,
             const LocationContext *LCtx)
-    : SimpleCall(CE, St, LCtx, CE_Block) {
-    assert(isa<BlockDataRegion>(getSVal(CE->getCallee()).getAsRegion()));
+    : SimpleCall(CE, St, LCtx, CE_Block) {}
+
+  /// \brief Returns the region associated with this instance of the block.
+  ///
+  /// This may be NULL if the block's origin is unknown.
+  const BlockDataRegion *getBlockRegion() const;
+
+  /// \brief Gets the declaration of the block.
+  ///
+  /// This is not an override of getDecl() because AnyFunctionCall has already
+  /// assumed that it's a FunctionDecl.
+  const BlockDecl *getBlockDecl() const {
+    const BlockDataRegion *BR = getBlockRegion();
+    if (!BR)
+      return 0;
+    return BR->getDecl();
   }
 
   static bool classof(const CallEvent *CA) {
     return CA->getKind() == CE_Block;
   }
-
-private:
-  const BlockDataRegion *getBlockRegion() const;
 };
 
 /// \brief Represents a call to a C++ constructor.

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=159560&r1=159559&r2=159560&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h Mon Jul  2 14:28:09 2012
@@ -42,6 +42,7 @@
 
 class AnalysisManager;
 class CallEvent;
+class SimpleCall;
 class ObjCMethodCall;
 
 class ExprEngine : public SubEngine {
@@ -468,6 +469,11 @@
   void evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, const Expr *StoreE,
                  ExplodedNode *Pred, ProgramStateRef St, SVal TargetLV, SVal Val,
                  const ProgramPointTag *tag = 0);
+
+  void evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+                const SimpleCall &Call);
+  void defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+                       const CallEvent &Call);
 private:
   void evalLoadCommon(ExplodedNodeSet &Dst,
                       const Expr *NodeEx,  /* Eventually will be a CFGStmt */
@@ -488,7 +494,8 @@
                     const ProgramPointTag *tag, bool isLoad);
 
   bool shouldInlineDecl(const Decl *D, ExplodedNode *Pred);
-  bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred);
+  bool inlineCall(ExplodedNodeSet &Dst, const CallEvent &Call,
+                  ExplodedNode *Pred);
 
   bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC);
 };

Modified: cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp?rev=159560&r1=159559&r2=159560&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp Mon Jul  2 14:28:09 2012
@@ -307,23 +307,34 @@
   const Expr *Callee = getOriginExpr()->getCallee();
   const MemRegion *DataReg = getSVal(Callee).getAsRegion();
 
-  return cast<BlockDataRegion>(DataReg);
+  return dyn_cast_or_null<BlockDataRegion>(DataReg);
 }
 
 CallEvent::param_iterator BlockCall::param_begin() const {
-  return getBlockRegion()->getDecl()->param_begin();
+  const BlockDecl *D = getBlockDecl();
+  if (!D)
+    return 0;
+  return D->param_begin();
 }
 
 CallEvent::param_iterator BlockCall::param_end() const {
-  return getBlockRegion()->getDecl()->param_end();
+  const BlockDecl *D = getBlockDecl();
+  if (!D)
+    return 0;
+  return D->param_end();
 }
 
 void BlockCall::addExtraInvalidatedRegions(RegionList &Regions) const {
-  Regions.push_back(getBlockRegion());
+  // FIXME: This also needs to invalidate captured globals.
+  if (const MemRegion *R = getBlockRegion())
+    Regions.push_back(R);
 }
 
 QualType BlockCall::getDeclaredResultType() const {
-  QualType BlockTy = getBlockRegion()->getCodeRegion()->getLocationType();
+  const BlockDataRegion *BR = getBlockRegion();
+  if (!BR)
+    return QualType();
+  QualType BlockTy = BR->getCodeRegion()->getLocationType();
   return cast<FunctionType>(BlockTy->getPointeeType())->getResultType();
 }
 

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp?rev=159560&r1=159559&r2=159560&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp Mon Jul  2 14:28:09 2012
@@ -461,16 +461,9 @@
 /// Only one checker will evaluate the call.
 void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
                                             const ExplodedNodeSet &Src,
-                                            const CallExpr *CE,
-                                            ExprEngine &Eng,
-                                            GraphExpander *defaultEval) {
-  if (EvalCallCheckers.empty()   &&
-      InlineCallCheckers.empty() &&
-      defaultEval == 0) {
-    Dst.insert(Src);
-    return;
-  }
-
+                                            const SimpleCall &Call,
+                                            ExprEngine &Eng) {
+  const CallExpr *CE = Call.getOriginExpr();
   for (ExplodedNodeSet::iterator
          NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) {
 
@@ -533,12 +526,8 @@
     }
     
     // If none of the checkers evaluated the call, ask ExprEngine to handle it.
-    if (!anyEvaluated) {
-      if (defaultEval)
-        defaultEval->expandGraph(Dst, Pred);
-      else
-        Dst.insert(Pred);
-    }
+    if (!anyEvaluated)
+      Eng.defaultEvalCall(Dst, Pred, Call);
   }
 }
 
@@ -678,6 +667,3 @@
   for (unsigned i = 0, e = CheckerDtors.size(); i != e; ++i)
     CheckerDtors[i]();
 }
-
-// Anchor for the vtable.
-GraphExpander::~GraphExpander() { }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=159560&r1=159559&r2=159560&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Mon Jul  2 14:28:09 2012
@@ -207,6 +207,10 @@
 
 // Determine if we should inline the call.
 bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) {
+  // FIXME: default constructors don't have bodies.
+  if (!D->hasBody())
+    return false;
+
   AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
   const CFG *CalleeCFG = CalleeADC->getCFG();
 
@@ -235,52 +239,47 @@
       return false;
   }
 
+  // Do not inline constructors until we can model destructors.
+  // This is unfortunate, but basically necessary for smart pointers and such.
+  if (isa<CXXConstructorDecl>(D))
+    return false;
+
   return true;
 }
 
-bool ExprEngine::InlineCall(ExplodedNodeSet &Dst,
-                            const CallExpr *CE, 
+bool ExprEngine::inlineCall(ExplodedNodeSet &Dst,
+                            const CallEvent &Call,
                             ExplodedNode *Pred) {
   if (!getAnalysisManager().shouldInlineCall())
     return false;
 
-  //  if (!shouldInlineCallExpr(CE, this))
-  //    return false;
-
   const StackFrameContext *CallerSFC =
     Pred->getLocationContext()->getCurrentStackFrame();
 
-  ProgramStateRef state = Pred->getState();
-  const Expr *Callee = CE->getCallee();
-  SVal CalleeVal = state->getSVal(Callee, Pred->getLocationContext());
-  const Decl *D = 0;
+  const Decl *D = Call.getDecl();
   const LocationContext *ParentOfCallee = 0;
-  
-  if (const FunctionDecl *FD = CalleeVal.getAsFunctionDecl()) {
-    if (!FD->hasBody(FD))
+
+  switch (Call.getKind()) {
+  case CE_Function:
+  case CE_CXXConstructor:
+  case CE_CXXMember:
+    // These are always at least possible to inline.
+    break;
+  case CE_Block: {
+    const BlockDataRegion *BR = cast<BlockCall>(Call).getBlockRegion();
+    if (!BR)
       return false;
-  
-    switch (CE->getStmtClass()) {
-      default:
-        break;
-      case Stmt::CXXMemberCallExprClass:
-      case Stmt::CallExprClass: {
-        D = FD;
-        break;
-        
-      }
-    }
-  } else if (const BlockDataRegion *BR =
-              dyn_cast_or_null<BlockDataRegion>(CalleeVal.getAsRegion())) {
-    assert(CE->getStmtClass() == Stmt::CallExprClass);
-    const BlockDecl *BD = BR->getDecl();
-    D = BD;
-    AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(BD);
+    D = BR->getDecl();
+    AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(D);
     ParentOfCallee = BlockCtx->getBlockInvocationContext(CallerSFC,
-                                                         BD,
+                                                         cast<BlockDecl>(D),
                                                          BR);
-  } else {
-    // This is case we don't handle yet.
+    break;
+  }
+  case CE_ObjCMessage:
+  case CE_ObjCPropertyAccess:
+    // These always use dynamic dispatch; enabling inlining means assuming
+    // that a particular method will be called at runtime.
     return false;
   }
   
@@ -290,16 +289,19 @@
   if (!ParentOfCallee)
     ParentOfCallee = CallerSFC;
 
+  const Expr *CallE = Call.getOriginExpr();
+  assert(CallE && "It is not yet possible to have calls without statements");
+
   // Construct a new stack frame for the callee.
   AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D);
   const StackFrameContext *CalleeSFC =
-    CalleeADC->getStackFrame(ParentOfCallee, CE,
+    CalleeADC->getStackFrame(ParentOfCallee, CallE,
                              currentBuilderContext->getBlock(),
                              currentStmtIdx);
   
-  CallEnter Loc(CE, CalleeSFC, Pred->getLocationContext());
+  CallEnter Loc(CallE, CalleeSFC, Pred->getLocationContext());
   bool isNew;
-  if (ExplodedNode *N = G.getNode(Loc, state, false, &isNew)) {
+  if (ExplodedNode *N = G.getNode(Loc, Pred->getState(), false, &isNew)) {
     N->addPredecessor(Pred, G);
     if (isNew)
       Engine.getWorkList()->enqueue(N);
@@ -307,13 +309,13 @@
   return true;
 }
 
-static ProgramStateRef getReplayWithoutInliningState(ExplodedNode *&N,
-                                                     const CallExpr *CE) {
+static ProgramStateRef getInlineFailedState(ExplodedNode *&N,
+                                            const Stmt *CallE) {
   void *ReplayState = N->getState()->get<ReplayWithoutInlining>();
   if (!ReplayState)
     return 0;
-  const CallExpr *ReplayCE = reinterpret_cast<const CallExpr*>(ReplayState);
-  if (CE == ReplayCE) {
+  const Stmt *ReplayCallE = reinterpret_cast<const Stmt *>(ReplayState);
+  if (CallE == ReplayCallE) {
     return N->getState()->remove<ReplayWithoutInlining>();
   }
   return 0;
@@ -324,83 +326,75 @@
   // Perform the previsit of the CallExpr.
   ExplodedNodeSet dstPreVisit;
   getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, CE, *this);
-  
-  // Now evaluate the call itself.
-  class DefaultEval : public GraphExpander {
-    ExprEngine &Eng;
-    const CallExpr *CE;
-  public:
-    
-    DefaultEval(ExprEngine &eng, const CallExpr *ce)
-    : Eng(eng), CE(ce) {}
-    virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) {
-
-      ProgramStateRef state = getReplayWithoutInliningState(Pred, CE);
-
-      // First, try to inline the call.
-      if (state == 0 && Eng.InlineCall(Dst, CE, Pred))
-        return;
-
-      // First handle the return value.
-      StmtNodeBuilder Bldr(Pred, Dst, *Eng.currentBuilderContext);
-
-      // Get the callee.
-      const Expr *Callee = CE->getCallee()->IgnoreParens();
-      if (state == 0)
-        state = Pred->getState();
-      SVal L = state->getSVal(Callee, Pred->getLocationContext());
-
-      // Figure out the result type. We do this dance to handle references.
-      // FIXME: This doesn't handle C++ methods, blocks, etc.
-      QualType ResultTy;
-      if (const FunctionDecl *FD = L.getAsFunctionDecl())
-        ResultTy = FD->getResultType();
-      else
-        ResultTy = CE->getType();
-
-      if (CE->isGLValue())
-        ResultTy = Eng.getContext().getPointerType(ResultTy);
-
-      // Conjure a symbol value to use as the result.
-      SValBuilder &SVB = Eng.getSValBuilder();
-      unsigned Count = Eng.currentBuilderContext->getCurrentBlockCount();
-      const LocationContext *LCtx = Pred->getLocationContext();
-      SVal RetVal = SVB.getConjuredSymbolVal(0, CE, LCtx, ResultTy, Count);
-
-      // Generate a new state with the return value set.
-      state = state->BindExpr(CE, LCtx, RetVal);
-
-      // Invalidate the arguments.
-      if (const CXXMemberCallExpr *MemberCE = dyn_cast<CXXMemberCallExpr>(CE)) {
-        CXXMemberCall Call(MemberCE, state, LCtx);
-        state = Call.invalidateRegions(Count);
-      } else if (isa<BlockDataRegion>(L.getAsRegion())) {
-        BlockCall Call(CE, state, LCtx);
-        state = Call.invalidateRegions(Count);
-      } else {
-        FunctionCall Call(CE, state, LCtx);
-        state = Call.invalidateRegions(Count);
-      }
 
-      // And make the result node.
-      Bldr.generateNode(CE, Pred, state);
-    }
-  };
-  
-  // Finally, evaluate the function call.  We try each of the checkers
+  // Get the callee kind.
+  const CXXMemberCallExpr *MemberCE = dyn_cast<CXXMemberCallExpr>(CE);
+  bool IsBlock = (MemberCE ? false
+                           : CE->getCallee()->getType()->isBlockPointerType());
+
+  // Evaluate the function call.  We try each of the checkers
   // to see if the can evaluate the function call.
   ExplodedNodeSet dstCallEvaluated;
-  DefaultEval defEval(*this, CE);
-  getCheckerManager().runCheckersForEvalCall(dstCallEvaluated,
-                                             dstPreVisit,
-                                             CE, *this, &defEval);
-  
+  for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
+       I != E; ++I) {
+    ProgramStateRef State = (*I)->getState();
+    const LocationContext *LCtx = (*I)->getLocationContext();
+
+    // Evaluate the call.
+    if (MemberCE)
+      evalCall(dstCallEvaluated, *I, CXXMemberCall(MemberCE, State, LCtx));
+    else if (IsBlock)
+      evalCall(dstCallEvaluated, *I, BlockCall(CE, State, LCtx));
+    else
+      evalCall(dstCallEvaluated, *I, FunctionCall(CE, State, LCtx));
+  }
+
   // Finally, perform the post-condition check of the CallExpr and store
   // the created nodes in 'Dst'.
+  // Note that if the call was inlined, dstCallEvaluated will be empty.
+  // The post-CallExpr check will occur in processCallExit.
   getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE,
                                              *this);
 }
 
+void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+                          const SimpleCall &Call) {
+  getCheckerManager().runCheckersForEvalCall(Dst, Pred, Call, *this);
+}
+
+void ExprEngine::defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
+                                 const CallEvent &Call) {
+  // Try to inline the call.
+  ProgramStateRef state = 0;
+  const Expr *E = Call.getOriginExpr();
+  if (E) {
+    state = getInlineFailedState(Pred, E);
+    if (state == 0 && inlineCall(Dst, Call, Pred))
+      return;
+  }
+
+  // If we can't inline it, handle the return value and invalidate the regions.
+  StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
+
+  // 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.
+  assert(Call.getOriginExpr() && "Must have an expression to bind the result");
+  QualType ResultTy = Call.getResultType();
+  SValBuilder &SVB = getSValBuilder();
+  const LocationContext *LCtx = Pred->getLocationContext();
+  SVal RetVal = SVB.getConjuredSymbolVal(0, Call.getOriginExpr(), LCtx,
+                                         ResultTy, Count);
+
+  // And make the result node.
+  state = state->BindExpr(Call.getOriginExpr(), LCtx, RetVal);
+  Bldr.generateNode(Call.getOriginExpr(), Pred, state);
+}
+
 void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
                                  ExplodedNodeSet &Dst) {
   





More information about the cfe-commits mailing list