[cfe-commits] r47100 - in /cfe/trunk: Analysis/GRCoreEngine.cpp Analysis/GRExprEngine.cpp include/clang/Analysis/PathSensitive/ExplodedGraph.h include/clang/Analysis/PathSensitive/GRCoreEngine.h

Ted Kremenek kremenek at apple.com
Wed Feb 13 15:08:21 PST 2008


Author: kremenek
Date: Wed Feb 13 17:08:21 2008
New Revision: 47100

URL: http://llvm.org/viewvc/llvm-project?rev=47100&view=rev
Log:
Added support to GRCoreEngine/GRExprEngine for processing control-flow
from switch...case...default statements.

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

Modified: cfe/trunk/Analysis/GRCoreEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Analysis/GRCoreEngine.cpp?rev=47100&r1=47099&r2=47100&view=diff

==============================================================================
--- cfe/trunk/Analysis/GRCoreEngine.cpp (original)
+++ cfe/trunk/Analysis/GRCoreEngine.cpp Wed Feb 13 17:08:21 2008
@@ -213,6 +213,15 @@
         return;
       }
         
+      case Stmt::SwitchStmtClass: {
+        GRSwitchNodeBuilderImpl builder(Pred, B,
+                                        cast<SwitchStmt>(Term)->getCond(),
+                                        this);
+        
+        ProcessSwitch(builder);
+        return;
+      }
+        
       case Stmt::WhileStmtClass:
         HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
         return;
@@ -386,3 +395,49 @@
                        
   return NULL;
 }
+
+
+ExplodedNodeImpl*
+GRSwitchNodeBuilderImpl::generateCaseStmtNodeImpl(const Iterator& I, void* St) {
+
+  bool IsNew;
+  
+  ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(BlockEdge(Eng.getCFG(), Src,
+                                                        I.getBlock()),
+                                              St, &IsNew);  
+  Succ->addPredecessor(Pred);
+  
+  if (IsNew) {
+    Eng.WList->Enqueue(Succ);
+    return Succ;
+  }
+  
+  return NULL;
+}
+
+
+ExplodedNodeImpl*
+GRSwitchNodeBuilderImpl::generateDefaultCaseNodeImpl(void* St, bool isSink) {
+  
+  // Get the block for the default case.
+  assert (Src->succ_rbegin() != Src->succ_rend());
+  CFGBlock* DefaultBlock = *Src->succ_rbegin();
+  
+  bool IsNew;
+  
+  ExplodedNodeImpl* Succ = Eng.G->getNodeImpl(BlockEdge(Eng.getCFG(), Src,
+                                                        DefaultBlock),
+                                              St, &IsNew);  
+  Succ->addPredecessor(Pred);
+  
+  if (IsNew) {
+    if (isSink)
+      Succ->markAsSink();
+    else
+      Eng.WList->Enqueue(Succ);
+    
+    return Succ;
+  }
+  
+  return NULL;
+}

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

==============================================================================
--- cfe/trunk/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/Analysis/GRExprEngine.cpp Wed Feb 13 17:08:21 2008
@@ -65,11 +65,15 @@
     
 public:
   typedef ValueStateManager::StateTy StateTy;
+  typedef ExplodedGraph<GRExprEngine> GraphTy;
+  typedef GraphTy::NodeTy NodeTy;
+  
+  // Builders.
   typedef GRStmtNodeBuilder<GRExprEngine> StmtNodeBuilder;
   typedef GRBranchNodeBuilder<GRExprEngine> BranchNodeBuilder;
   typedef GRIndirectGotoNodeBuilder<GRExprEngine> IndirectGotoNodeBuilder;
-  typedef ExplodedGraph<GRExprEngine> GraphTy;
-  typedef GraphTy::NodeTy NodeTy;
+  typedef GRSwitchNodeBuilder<GRExprEngine> SwitchNodeBuilder;
+  
   
   class NodeSet {
     typedef llvm::SmallVector<NodeTy*,3> ImplTy;
@@ -197,6 +201,10 @@
   ///  nodes by processing the 'effects' of a computed goto jump.
   void ProcessIndirectGoto(IndirectGotoNodeBuilder& builder);
   
+  /// ProcessSwitch - Called by GRCoreEngine.  Used to generate successor
+  ///  nodes by processing the 'effects' of a switch statement.
+  void ProcessSwitch(SwitchNodeBuilder& builder);  
+  
   /// RemoveDeadBindings - Return a new state that is the same as 'St' except
   ///  that all subexpression mappings are removed and that any
   ///  block-level expressions that are not live at 'S' also have their
@@ -474,6 +482,97 @@
     builder.generateNode(I, St);
 }
 
+/// ProcessSwitch - Called by GRCoreEngine.  Used to generate successor
+///  nodes by processing the 'effects' of a switch statement.
+void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) {
+  
+  typedef SwitchNodeBuilder::iterator iterator;
+  
+  StateTy St = builder.getState();  
+  NonLValue CondV = cast<NonLValue>(GetValue(St, builder.getCondition()));
+
+  if (isa<UninitializedVal>(CondV)) {
+    NodeTy* N = builder.generateDefaultCaseNode(St, true);
+    UninitBranches.insert(N);
+    return;
+  }
+  
+  StateTy  DefaultSt = St;
+  
+  // While most of this can be assumed (such as the signedness), having it
+  // just computed makes sure everything makes the same assumptions end-to-end.
+  unsigned bits = getContext().getTypeSize(getContext().IntTy,SourceLocation());
+  APSInt V1(bits, false);
+  APSInt V2 = V1;
+  
+  for (iterator I=builder.begin(), E=builder.end(); I!=E; ++I) {
+
+    CaseStmt* Case = cast<CaseStmt>(I.getCase());
+    
+    // Evaluate the case.
+    if (!Case->getLHS()->isIntegerConstantExpr(V1, getContext(), 0, true)) {
+      assert (false && "Case condition must evaluate to an integer constant.");
+      return;
+    }
+    
+    // Get the RHS of the case, if it exists.
+    
+    if (Expr* E = Case->getRHS()) {
+      if (!E->isIntegerConstantExpr(V2, getContext(), 0, true)) {
+        assert (false &&
+                "Case condition (RHS) must evaluate to an integer constant.");
+        return ;
+      }
+      
+      assert (V1 <= V2);
+    }
+    else V2 = V1;
+    
+    // FIXME: Eventually we should replace the logic below with a range
+    //  comparison, rather than concretize the values within the range.
+    //  This should be easy once we have "ranges" for NonLValues.
+        
+    do {      
+      nonlval::ConcreteInt CaseVal(ValMgr.getValue(V1));
+      
+      NonLValue Result =
+        CondV.EvalBinaryOp(ValMgr, BinaryOperator::EQ, CaseVal);
+      
+      // Now "assume" that the case matches.
+      bool isFeasible;
+      
+      StateTy StNew = Assume(St, Result, true, isFeasible);
+      
+      if (isFeasible) {
+        builder.generateCaseStmtNode(I, StNew);
+       
+        // If CondV evaluates to a constant, then we know that this
+        // is the *only* case that we can take, so stop evaluating the
+        // others.
+        if (isa<nonlval::ConcreteInt>(CondV))
+          return;
+      }
+      
+      // Now "assume" that the case doesn't match.  Add this state
+      // to the default state (if it is feasible).
+      
+      StNew = Assume(DefaultSt, Result, false, isFeasible);
+      
+      if (isFeasible)
+        DefaultSt = StNew;
+
+      // Concretize the next value in the range.      
+      ++V1;
+      
+    } while (V1 < V2);
+  }
+  
+  // If we reach here, than we know that the default branch is
+  // possible.  
+  builder.generateDefaultCaseNode(DefaultSt);
+}
+
+
 void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred,
                                    NodeSet& Dst) {
 
@@ -861,8 +960,8 @@
 }
 
 void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
-                                      GRExprEngine::NodeTy* Pred,
-                                      GRExprEngine::NodeSet& Dst) {
+                                       GRExprEngine::NodeTy* Pred,
+                                       GRExprEngine::NodeSet& Dst) {
   NodeSet S1;
   
   if (B->isAssignmentOp())
@@ -1354,7 +1453,30 @@
           Out << "\\|Terminator: ";
           E.getSrc()->printTerminator(Out);
           
-          if (isa<SwitchStmt>(T) || isa<IndirectGotoStmt>(T)) {
+          if (isa<SwitchStmt>(T)) {
+            Stmt* Label = E.getDst()->getLabel();
+            
+            if (Label) {                        
+              if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
+                Out << "\\lcase ";
+                C->getLHS()->printPretty(Out);
+                
+                if (Stmt* RHS = C->getRHS()) {
+                  Out << " .. ";
+                  RHS->printPretty(Out);
+                }
+                
+                Out << ":";
+              }
+              else {
+                assert (isa<DefaultStmt>(Label));
+                Out << "\\ldefault:";
+              }
+            }
+            else 
+              Out << "\\l(implicit) default:";
+          }
+          else if (isa<IndirectGotoStmt>(T)) {
             // FIXME
           }
           else {

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

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/ExplodedGraph.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/ExplodedGraph.h Wed Feb 13 17:08:21 2008
@@ -31,6 +31,7 @@
 class GRStmtNodeBuilderImpl;
 class GRBranchNodeBuilderImpl;
 class GRIndirectGotoNodeBuilderImpl;
+class GRSwitchNodeBuilderImpl;
 class CFG;
 class ASTContext;
 class FunctionDecl;
@@ -43,6 +44,7 @@
   friend class GRStmtNodeBuilderImpl;
   friend class GRBranchNodeBuilderImpl;
   friend class GRIndirectGotoNodeBuilderImpl;
+  friend class GRSwitchNodeBuilderImpl;
   
   class NodeGroup {
     enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 };
@@ -198,6 +200,7 @@
   friend class GRStmtNodeBuilderImpl;
   friend class GRBranchNodeBuilderImpl;
   friend class GRIndirectGotoNodeBuilderImpl;
+  friend class GRSwitchNodeBuilderImpl;
   
   // Type definitions.
   typedef llvm::DenseMap<ProgramPoint,void*>        EdgeNodeSetMap;

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

==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h Wed Feb 13 17:08:21 2008
@@ -27,8 +27,8 @@
 class GRStmtNodeBuilderImpl;
 class GRBranchNodeBuilderImpl;
 class GRIndirectGotoNodeBuilderImpl;
+class GRSwitchNodeBuilderImpl;
 class GRWorkList;
-class LabelStmt;
 
 //===----------------------------------------------------------------------===//
 /// GRCoreEngineImpl - Implements the core logic of the graph-reachability analysis.
@@ -44,6 +44,7 @@
   friend class GRStmtNodeBuilderImpl;
   friend class GRBranchNodeBuilderImpl;
   friend class GRIndirectGotoNodeBuilderImpl;
+  friend class GRSwitchNodeBuilderImpl;
   
   typedef llvm::DenseMap<Stmt*,Stmt*> ParentMapTy;
     
@@ -93,6 +94,8 @@
                               GRBranchNodeBuilderImpl& Builder) = 0;
 
   virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0;
+  
+  virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& Builder) = 0;
 
 private:
   GRCoreEngineImpl(const GRCoreEngineImpl&); // Do not implement.
@@ -331,6 +334,79 @@
     return GRTrait<StateTy>::toState(NB.getState());
   }    
 };
+  
+class GRSwitchNodeBuilderImpl {
+  GRCoreEngineImpl& Eng;
+  CFGBlock* Src;
+  Expr* Condition;
+  ExplodedNodeImpl* Pred;  
+public:
+  GRSwitchNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
+                          Expr* condition, GRCoreEngineImpl* eng)
+  : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
+  
+  class Iterator {
+    CFGBlock::succ_reverse_iterator I;
+    
+    friend class GRSwitchNodeBuilderImpl;    
+    Iterator(CFGBlock::succ_reverse_iterator i) : I(i) {}    
+  public:
+    
+    Iterator& operator++() { ++I; return *this; }
+    bool operator!=(const Iterator& X) const { return I != X.I; }
+    
+    CaseStmt* getCase() const {
+      return llvm::cast<CaseStmt>((*I)->getLabel());
+    }
+    
+    CFGBlock* getBlock() const {
+      return *I;
+    }
+  };
+  
+  Iterator begin() { return Iterator(Src->succ_rbegin()+1); }
+  Iterator end() { return Iterator(Src->succ_rend()); }
+  
+  ExplodedNodeImpl* generateCaseStmtNodeImpl(const Iterator& I, void* State);
+  ExplodedNodeImpl* generateDefaultCaseNodeImpl(void* State, bool isSink);
+  
+  inline Expr* getCondition() const { return Condition; }
+  inline void* getState() const { return Pred->State; }
+};
+
+template<typename CHECKER>
+class GRSwitchNodeBuilder {
+  typedef CHECKER                                CheckerTy; 
+  typedef typename CheckerTy::StateTy            StateTy;
+  typedef ExplodedGraph<CheckerTy>               GraphTy;
+  typedef typename GraphTy::NodeTy               NodeTy;
+  
+  GRSwitchNodeBuilderImpl& NB;
+  
+public:
+  GRSwitchNodeBuilder(GRSwitchNodeBuilderImpl& nb) : NB(nb) {}
+  
+  typedef GRSwitchNodeBuilderImpl::Iterator     iterator;
+  
+  inline iterator begin() { return NB.begin(); }
+  inline iterator end() { return NB.end(); }
+  
+  inline Expr* getCondition() const { return NB.getCondition(); }
+  
+  inline NodeTy* generateCaseStmtNode(const iterator& I, StateTy St) {
+    void *state = GRTrait<StateTy>::toPtr(St);        
+    return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, state));
+  }
+  
+  inline NodeTy* generateDefaultCaseNode(StateTy St, bool isSink = false) {    
+    void *state = GRTrait<StateTy>::toPtr(St);        
+    return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(state, isSink));
+  }
+  
+  inline StateTy getState() const {
+    return GRTrait<StateTy>::toState(NB.getState());
+  }    
+};
 
   
 template<typename CHECKER>
@@ -371,6 +447,11 @@
     Checker->ProcessIndirectGoto(Builder);
   }
   
+  virtual void ProcessSwitch(GRSwitchNodeBuilderImpl& BuilderImpl) {
+    GRSwitchNodeBuilder<CHECKER> Builder(BuilderImpl);
+    Checker->ProcessSwitch(Builder);
+  }
+  
 public:  
   /// Construct a GRCoreEngine object to analyze the provided CFG using
   ///  a DFS exploration of the exploded graph.





More information about the cfe-commits mailing list