[cfe-commits] r90296 - in /cfe/trunk: include/clang/Analysis/PathSensitive/Checker.h include/clang/Analysis/PathSensitive/GRExprEngine.h include/clang/Analysis/PathSensitive/GRTransferFuncs.h lib/Analysis/CFRefCount.cpp lib/Analysis/CallAndMessageChecker.cpp lib/Analysis/GRExprEngine.cpp

Zhongxing Xu xuzhongxing at gmail.com
Tue Dec 1 21:49:12 PST 2009


Author: zhongxingxu
Date: Tue Dec  1 23:49:12 2009
New Revision: 90296

URL: http://llvm.org/viewvc/llvm-project?rev=90296&view=rev
Log:
Hard bifurcate the state into nil receiver and non-nil receiver, so that
we don't need to use the DoneEvaluation hack when check for 
ObjCMessageExpr.

PreVisitObjCMessageExpr() only checks for undefined receiver or arguments.

Add checker interface EvalNilReceiver(). This is a 'once-and-done' interface.


Modified:
    cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h
    cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
    cfe/trunk/include/clang/Analysis/PathSensitive/GRTransferFuncs.h
    cfe/trunk/lib/Analysis/CFRefCount.cpp
    cfe/trunk/lib/Analysis/CallAndMessageChecker.cpp
    cfe/trunk/lib/Analysis/GRExprEngine.cpp

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

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/Checker.h Tue Dec  1 23:49:12 2009
@@ -53,22 +53,10 @@
       OldTag(B.Tag, tag),
       OldPointKind(B.PointKind, K),
       OldHasGen(B.HasGeneratedNode),
-      state(st), statement(stmt), size(Dst.size()),
-      DoneEvaluating(false) {}
+      state(st), statement(stmt), size(Dst.size()) {}
 
   ~CheckerContext();
   
-  // FIXME: This were added to support CallAndMessageChecker to indicating
-  // to GRExprEngine to "stop evaluating" a message expression under certain
-  // cases.  This is *not* meant to be a permanent API change, and was added
-  // to aid in the transition of removing logic for checks from GRExprEngine.  
-  void setDoneEvaluating() {
-    DoneEvaluating = true;
-  }
-  bool isDoneEvaluating() const {
-    return DoneEvaluating;
-  }
-  
   ConstraintManager &getConstraintManager() {
       return Eng.getConstraintManager();
   }
@@ -165,7 +153,7 @@
   friend class GRExprEngine;
 
   // FIXME: Remove the 'tag' option.
-  bool GR_Visit(ExplodedNodeSet &Dst,
+  void GR_Visit(ExplodedNodeSet &Dst,
                 GRStmtNodeBuilder &Builder,
                 GRExprEngine &Eng,
                 const Stmt *S,
@@ -177,7 +165,14 @@
       _PreVisit(C, S);
     else
       _PostVisit(C, S);
-    return C.isDoneEvaluating();
+  }
+
+  bool GR_EvalNilReceiver(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder,
+                          GRExprEngine &Eng, const ObjCMessageExpr *ME,
+                          ExplodedNode *Pred, const GRState *state, void *tag) {
+    CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
+                     ME, state);
+    return EvalNilReceiver(C, ME);
   }
 
   // FIXME: Remove the 'tag' option.
@@ -231,6 +226,10 @@
   virtual void VisitBranchCondition(GRBranchNodeBuilder &Builder,
                                     GRExprEngine &Eng,
                                     Stmt *Condition, void *tag) {}
+
+  virtual bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME) {
+    return false;
+  }
 };
 } // end clang namespace
 

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=90296&r1=90295&r2=90296&view=diff

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h Tue Dec  1 23:49:12 2009
@@ -209,8 +209,13 @@
 protected:
   /// CheckerVisit - Dispatcher for performing checker-specific logic
   ///  at specific statements.
-  bool CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, 
+  void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, 
                     bool isPrevisit);
+
+  void CheckerEvalNilReceiver(const ObjCMessageExpr *ME, 
+                              ExplodedNodeSet &Dst,
+                              const GRState *state,
+                              ExplodedNode *Pred);
   
   void CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
                         ExplodedNodeSet &Dst, ExplodedNodeSet &Src, 
@@ -358,9 +363,10 @@
   }
   
 protected:
-  void EvalObjCMessageExpr(ExplodedNodeSet& Dst, ObjCMessageExpr* ME, ExplodedNode* Pred) {
+  void EvalObjCMessageExpr(ExplodedNodeSet& Dst, ObjCMessageExpr* ME, 
+                           ExplodedNode* Pred, const GRState *state) {
     assert (Builder && "GRStmtNodeBuilder must be defined.");
-    getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred);
+    getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred, state);
   }
 
   const GRState* MarkBranch(const GRState* St, Stmt* Terminator,

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

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRTransferFuncs.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRTransferFuncs.h Tue Dec  1 23:49:12 2009
@@ -47,7 +47,8 @@
                                    GRExprEngine& Engine,
                                    GRStmtNodeBuilder& Builder,
                                    ObjCMessageExpr* ME,
-                                   ExplodedNode* Pred) {}
+                                   ExplodedNode* Pred,
+                                   const GRState *state) {}
 
   // Stores.
 

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

==============================================================================
--- cfe/trunk/lib/Analysis/CFRefCount.cpp (original)
+++ cfe/trunk/lib/Analysis/CFRefCount.cpp Tue Dec  1 23:49:12 2009
@@ -1985,7 +1985,7 @@
                    Expr* Receiver,
                    const RetainSummary& Summ,
                    ExprIterator arg_beg, ExprIterator arg_end,
-                   ExplodedNode* Pred);
+                   ExplodedNode* Pred, const GRState *state);
 
   virtual void EvalCall(ExplodedNodeSet& Dst,
                         GRExprEngine& Eng,
@@ -1998,7 +1998,8 @@
                                    GRExprEngine& Engine,
                                    GRStmtNodeBuilder& Builder,
                                    ObjCMessageExpr* ME,
-                                   ExplodedNode* Pred);
+                                   ExplodedNode* Pred,
+                                   const GRState *state);
 
   bool EvalObjCMessageExprAux(ExplodedNodeSet& Dst,
                               GRExprEngine& Engine,
@@ -2777,10 +2778,7 @@
                              Expr* Receiver,
                              const RetainSummary& Summ,
                              ExprIterator arg_beg, ExprIterator arg_end,
-                             ExplodedNode* Pred) {
-
-  // Get the state.
-  const GRState *state = Builder.GetState(Pred);
+                             ExplodedNode* Pred, const GRState *state) {
 
   // Evaluate the effect of the arguments.
   RefVal::Kind hasErr = (RefVal::Kind) 0;
@@ -3013,34 +3011,23 @@
 
   assert(Summ);
   EvalSummary(Dst, Eng, Builder, CE, 0, *Summ,
-              CE->arg_begin(), CE->arg_end(), Pred);
+              CE->arg_begin(), CE->arg_end(), Pred, Builder.GetState(Pred));
 }
 
 void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
                                      GRExprEngine& Eng,
                                      GRStmtNodeBuilder& Builder,
                                      ObjCMessageExpr* ME,
-                                     ExplodedNode* Pred) {
-  // FIXME: Since we moved the nil check into a checker, we could get nil
-  // receiver here. Need a better way to check such case. 
-  if (Expr* Receiver = ME->getReceiver()) {
-    const GRState *state = Pred->getState();
-    DefinedOrUnknownSVal L=cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
-    if (!state->Assume(L, true)) {
-      Dst.Add(Pred);
-      return;
-    }
-  }
-  
+                                     ExplodedNode* Pred,
+                                     const GRState *state) {
   RetainSummary *Summ =
     ME->getReceiver()
-      ? Summaries.getInstanceMethodSummary(ME, Builder.GetState(Pred),
-                                           Pred->getLocationContext())
+      ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext())
       : Summaries.getClassMethodSummary(ME);
 
   assert(Summ && "RetainSummary is null");
   EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ,
-              ME->arg_begin(), ME->arg_end(), Pred);
+              ME->arg_begin(), ME->arg_end(), Pred, state);
 }
 
 namespace {

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

==============================================================================
--- cfe/trunk/lib/Analysis/CallAndMessageChecker.cpp (original)
+++ cfe/trunk/lib/Analysis/CallAndMessageChecker.cpp Tue Dec  1 23:49:12 2009
@@ -41,6 +41,7 @@
 
   void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
   void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+  bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
 
 private:
   void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
@@ -148,28 +149,12 @@
       }
     }
   }
+}
 
-  // Check if the receiver was nil and then returns a value that may
-  // be garbage.
-  if (const Expr *Receiver = ME->getReceiver()) {
-    DefinedOrUnknownSVal receiverVal =
-      cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
-    
-    const GRState *notNullState, *nullState;
-    llvm::tie(notNullState, nullState) = state->Assume(receiverVal);
-    
-    if (nullState && !notNullState) {
-      HandleNilReceiver(C, nullState, ME);
-      C.setDoneEvaluating(); // FIXME: eventually remove.
-      return;
-    }
-    
-    assert(notNullState);
-    state = notNullState;
-  }
-  
-  // Add a state transition if the state has changed.
-  C.addTransition(state);
+bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C,
+                                            const ObjCMessageExpr *ME) {
+  HandleNilReceiver(C, C.getState(), ME);
+  return true; // Nil receiver is not handled elsewhere.
 }
 
 void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,

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

==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Tue Dec  1 23:49:12 2009
@@ -116,20 +116,18 @@
 // Checker worklist routines.
 //===----------------------------------------------------------------------===//
 
-bool GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
+void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
                                 ExplodedNodeSet &Src, bool isPrevisit) {
 
   if (Checkers.empty()) {
-    Dst.insert(Src);
-    return false;
+    Dst = Src;
+    return;
   }
 
   ExplodedNodeSet Tmp;
   ExplodedNodeSet *PrevSet = &Src;
-  bool stopProcessingAfterCurrentChecker = false;
 
-  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
-  {
+  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){
     ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst 
                                           : (PrevSet == &Tmp) ? &Src : &Tmp;
 
@@ -138,31 +136,26 @@
     Checker *checker = I->second;
     
     for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
-         NI != NE; ++NI) {
-      // FIXME: Halting evaluation of the checkers is something we may
-      // not support later.  The design is still evolving.      
-      if (checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI,
-                            tag, isPrevisit)) {
-        if (CurrSet != &Dst)
-          Dst.insert(*CurrSet);
-
-        stopProcessingAfterCurrentChecker = true;
-        continue;
-      }
-      assert(stopProcessingAfterCurrentChecker == false &&
-             "Inconsistent setting of 'stopProcessingAfterCurrentChecker'");
-    }
-    
-    if (stopProcessingAfterCurrentChecker)
-      return true;
-
-    // Continue on to the next checker.  Update the current NodeSet.
+         NI != NE; ++NI)
+      checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit);
     PrevSet = CurrSet;
   }
 
   // Don't autotransition.  The CheckerContext objects should do this
   // automatically.
-  return false;
+}
+
+void GRExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME, 
+                                          ExplodedNodeSet &Dst,
+                                          const GRState *state,
+                                          ExplodedNode *Pred) {
+  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
+    void *tag = I->first;
+    Checker *checker = I->second;
+
+    if (checker->GR_EvalNilReceiver(Dst, *Builder, *this, ME, Pred, state, tag))
+      break;
+  }
 }
 
 // FIXME: This is largely copy-paste from CheckerVisit().  Need to 
@@ -1922,10 +1915,7 @@
   ExplodedNodeSet Src, DstTmp;
   Src.Add(Pred);
   
-  if (CheckerVisit(ME, DstTmp, Src, true)) {
-    Dst.insert(DstTmp);
-    return;
-  }
+  CheckerVisit(ME, DstTmp, Src, true);
   
   unsigned size = Dst.size();
 
@@ -1934,10 +1924,38 @@
     Pred = *DI;
     bool RaisesException = false;
 
-    if (ME->getReceiver()) {
+    if (const Expr *Receiver = ME->getReceiver()) {
+      const GRState *state = Pred->getState();
+
+      // Bifurcate the state into nil and non-nil ones.
+      DefinedOrUnknownSVal receiverVal = 
+        cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
+
+      const GRState *notNilState, *nilState;
+      llvm::tie(notNilState, nilState) = state->Assume(receiverVal);
+
+      // There are three cases: can be nil or non-nil, must be nil, must be 
+      // non-nil. We handle must be nil, and merge the rest two into non-nil.
+      if (nilState && !notNilState) {
+        CheckerEvalNilReceiver(ME, Dst, nilState, Pred);
+        return;
+      }
+
+      assert(notNilState);
+
       // Check if the "raise" message was sent.
       if (ME->getSelector() == RaiseSel)
         RaisesException = true;
+
+      // Check if we raise an exception.  For now treat these as sinks.
+      // Eventually we will want to handle exceptions properly.
+      SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+      if (RaisesException)
+        Builder->BuildSinks = true;
+
+      // Dispatch to plug-in transfer function.
+      SaveOr OldHasGen(Builder->HasGeneratedNode);  
+      EvalObjCMessageExpr(Dst, ME, Pred, notNilState);
     }
     else {
 
@@ -1984,17 +2002,17 @@
             RaisesException = true; break;
           }
       }
-    }
 
-    // Check if we raise an exception.  For now treat these as sinks.  Eventually
-    // we will want to handle exceptions properly.
-    SaveAndRestore<bool> OldSink(Builder->BuildSinks);
-    if (RaisesException)
-      Builder->BuildSinks = true;
+      // Check if we raise an exception.  For now treat these as sinks.
+      // Eventually we will want to handle exceptions properly.
+      SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+      if (RaisesException)
+        Builder->BuildSinks = true;
 
-    // Dispatch to plug-in transfer function.
-    SaveOr OldHasGen(Builder->HasGeneratedNode);  
-    EvalObjCMessageExpr(Dst, ME, Pred);
+      // Dispatch to plug-in transfer function.
+      SaveOr OldHasGen(Builder->HasGeneratedNode);  
+      EvalObjCMessageExpr(Dst, ME, Pred, Builder->GetState(Pred));
+    }
   }
 
   // Handle the case where no nodes where generated.  Auto-generate that





More information about the cfe-commits mailing list