]> granicus.if.org Git - clang/commitdiff
Added support to GREngine/GRConstants for handling computed gotos.
authorTed Kremenek <kremenek@apple.com>
Wed, 13 Feb 2008 00:24:44 +0000 (00:24 +0000)
committerTed Kremenek <kremenek@apple.com>
Wed, 13 Feb 2008 00:24:44 +0000 (00:24 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@47038 91177308-0d34-0410-b5e6-96231b3b80d8

Analysis/GRConstants.cpp
Analysis/GREngine.cpp
include/clang/Analysis/PathSensitive/ExplodedGraph.h
include/clang/Analysis/PathSensitive/GREngine.h
include/clang/Analysis/ProgramPoint.h

index 86ac5ef1aab87d23fd0f41b3b47fe7adb34e7042..c2395512c59e416a0b1f6e4227ae0996a9445543 100644 (file)
@@ -67,6 +67,7 @@ public:
   typedef ValueStateManager::StateTy StateTy;
   typedef GRStmtNodeBuilder<GRConstants> StmtNodeBuilder;
   typedef GRBranchNodeBuilder<GRConstants> BranchNodeBuilder;
+  typedef GRIndirectGotoNodeBuilder<GRConstants> IndirectGotoNodeBuilder;
   typedef ExplodedGraph<GRConstants> GraphTy;
   typedef GraphTy::NodeTy NodeTy;
   
@@ -192,6 +193,10 @@ public:
   ///  nodes by processing the 'effects' of a branch condition.
   void ProcessBranch(Expr* Condition, Stmt* Term, BranchNodeBuilder& builder);
 
+  /// ProcessIndirectGoto - Called by GREngine.  Used to generate successor
+  ///  nodes by processing the 'effects' of a computed goto jump.
+  void ProcessIndirectGoto(IndirectGotoNodeBuilder& 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
@@ -424,6 +429,52 @@ void GRConstants::ProcessBranch(Expr* Condition, Stmt* Term,
     builder.markInfeasible(false);
 }
 
+/// ProcessIndirectGoto - Called by GREngine.  Used to generate successor
+///  nodes by processing the 'effects' of a computed goto jump.
+void GRConstants::ProcessIndirectGoto(IndirectGotoNodeBuilder& builder) {
+
+  StateTy St = builder.getState();  
+  LValue V = cast<LValue>(GetValue(St, builder.getTarget()));
+  
+  // Three possibilities:
+  //
+  //   (1) We know the computed label.
+  //   (2) The label is NULL (or some other constant), or Uninitialized.
+  //   (3) We have no clue about the label.  Dispatch to all targets.
+  //
+  
+  typedef IndirectGotoNodeBuilder::iterator iterator;
+
+  if (isa<lval::GotoLabel>(V)) {
+    LabelStmt* L = cast<lval::GotoLabel>(V).getLabel();
+    
+    for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) {
+      IndirectGotoNodeBuilder::Destination D = *I;
+      
+      if (D.getLabel() == L) {
+        builder.generateNode(D, St);
+        return;
+      }
+    }
+    
+    assert (false && "No block with label.");
+    return;
+  }
+
+  if (isa<lval::ConcreteInt>(V) || isa<UninitializedVal>(V)) {
+    // Dispatch to the first target and mark it as a sink.
+    NodeTy* N = builder.generateNode(*builder.begin(), St, true);
+    UninitBranches.insert(N);
+    return;
+  }
+  
+  // This is really a catch-all.  We don't support symbolics yet.
+  
+  assert (isa<UnknownVal>(V));
+  
+  for (iterator I=builder.begin(), E=builder.end(); I != E; ++I)
+    builder.generateNode(*I, St);
+}
 
 void GRConstants::VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred,
                                    NodeSet& Dst) {
@@ -1305,7 +1356,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRConstants::NodeTy*> :
           Out << "\\|Terminator: ";
           E.getSrc()->printTerminator(Out);
           
-          if (isa<SwitchStmt>(T)) {
+          if (isa<SwitchStmt>(T) || isa<IndirectGotoStmt>(T)) {
             // FIXME
           }
           else {
index e7720d97a3412580c4e4d47fef6bc83a5055201f..acce008cea95eca2f25210c93132b6ad8be466bc 100644 (file)
@@ -198,6 +198,18 @@ void GREngineImpl::HandleBlockExit(CFGBlock * B, ExplodedNodeImpl* Pred) {
       case Stmt::IfStmtClass:
         HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
         return;
+               
+      case Stmt::IndirectGotoStmtClass: {
+        // Only 1 successor: the indirect goto dispatch block.
+        assert (B->succ_size() == 1);
+        
+        GRIndirectGotoNodeBuilderImpl
+           builder(Pred, B, cast<IndirectGotoStmt>(Term)->getTarget(),
+                   *(B->succ_begin()), this);
+        
+        ProcessIndirectGoto(builder);
+        return;
+      }
         
       case Stmt::WhileStmtClass:
         HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
@@ -346,3 +358,46 @@ GRBranchNodeBuilderImpl::~GRBranchNodeBuilderImpl() {
   for (DeferredTy::iterator I=Deferred.begin(), E=Deferred.end(); I!=E; ++I)
     if (!(*I)->isSink()) Eng.WList->Enqueue(*I);
 }
+
+GRIndirectGotoNodeBuilderImpl::Destination
+GRIndirectGotoNodeBuilderImpl::Iterator::operator*() {
+  CFGBlock* B = *I;
+  assert (!B->empty());      
+  LabelStmt* L = cast<LabelStmt>(B->getLabel());
+  return Destination(L, *I);
+}
+
+GRIndirectGotoNodeBuilderImpl::Iterator
+GRIndirectGotoNodeBuilderImpl::begin() {
+  return Iterator(DispatchBlock.succ_begin());
+}
+
+GRIndirectGotoNodeBuilderImpl::Iterator
+GRIndirectGotoNodeBuilderImpl::end() {
+  return Iterator(DispatchBlock.succ_end());
+}
+
+ExplodedNodeImpl*
+GRIndirectGotoNodeBuilderImpl::generateNodeImpl(const Destination& D,
+                                                void* St,
+                                                bool isSink) {
+  bool IsNew;
+  
+  ExplodedNodeImpl* Succ =
+    Eng.G->getNodeImpl(BlockEdge(Eng.getCFG(), Src, D.getBlock(), true),
+                       St, &IsNew);
+              
+  Succ->addPredecessor(Pred);
+  
+  if (IsNew) {
+    
+    if (isSink)
+      Succ->markAsSink();
+    else
+      Eng.WList->Enqueue(Succ);
+    
+    return Succ;
+  }
+                       
+  return NULL;
+}
index dcc833c0dff85e3d116bbb7030408d2e102993a7..7b52003c6bfb0c5b1f5310e4491d23eea7e0d569 100644 (file)
@@ -30,6 +30,7 @@ class GREngineImpl;
 class ExplodedNodeImpl;
 class GRStmtNodeBuilderImpl;
 class GRBranchNodeBuilderImpl;
+class GRIndirectGotoNodeBuilderImpl;
 class CFG;
 class ASTContext;
 class FunctionDecl;
@@ -41,6 +42,7 @@ protected:
   friend class GREngineImpl;
   friend class GRStmtNodeBuilderImpl;
   friend class GRBranchNodeBuilderImpl;
+  friend class GRIndirectGotoNodeBuilderImpl;
   
   class NodeGroup {
     enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 };
@@ -195,6 +197,7 @@ protected:
   friend class GREngineImpl;
   friend class GRStmtNodeBuilderImpl;
   friend class GRBranchNodeBuilderImpl;
+  friend class GRIndirectGotoNodeBuilderImpl;
   
   // Type definitions.
   typedef llvm::DenseMap<ProgramPoint,void*>        EdgeNodeSetMap;
index 14ca1842da049b0d381c618e87a95ca742fe4d75..4e1f2095cb5aed6212453051ed81bc5ed367fb99 100644 (file)
@@ -24,12 +24,15 @@ namespace clang {
   
 class GRStmtNodeBuilderImpl;
 class GRBranchNodeBuilderImpl;
+class GRIndirectGotoNodeBuilderImpl;
 class GRWorkList;
+class LabelStmt;
   
 class GREngineImpl {
 protected:
   friend class GRStmtNodeBuilderImpl;
   friend class GRBranchNodeBuilderImpl;
+  friend class GRIndirectGotoNodeBuilderImpl;
   
   typedef llvm::DenseMap<Stmt*,Stmt*> ParentMapTy;
     
@@ -78,6 +81,7 @@ protected:
   virtual void  ProcessBranch(Expr* Condition, Stmt* Terminator,
                               GRBranchNodeBuilderImpl& Builder) = 0;
 
+  virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& Builder) = 0;
 
 private:
   GREngineImpl(const GREngineImpl&); // Do not implement.
@@ -246,6 +250,87 @@ public:
   }
 };
   
+class GRIndirectGotoNodeBuilderImpl {
+  GREngineImpl& Eng;
+  CFGBlock* Src;
+  CFGBlock& DispatchBlock;
+  Expr* E;
+  ExplodedNodeImpl* Pred;  
+public:
+  GRIndirectGotoNodeBuilderImpl(ExplodedNodeImpl* pred, CFGBlock* src,
+                                Expr* e, CFGBlock* dispatch,
+                                GREngineImpl* eng)
+  : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
+  
+  class Iterator;
+  
+  class Destination {
+    LabelStmt* L;
+    CFGBlock* B;
+
+    friend class Iterator;
+    Destination(LabelStmt* l, CFGBlock* b) : L(l), B(b) {}
+    
+  public:    
+    CFGBlock*  getBlock() const { return B; }
+    LabelStmt* getLabel() const { return L; }
+  };
+  
+  class Iterator {
+    CFGBlock::succ_iterator I;
+    
+    friend class GRIndirectGotoNodeBuilderImpl;    
+    Iterator(CFGBlock::succ_iterator i) : I(i) {}    
+  public:
+    
+    Iterator& operator++() { ++I; return *this; }
+    bool operator!=(const Iterator& X) const { return I != X.I; }
+    
+    Destination operator*();
+  };
+  
+  Iterator begin();
+  Iterator end();
+  
+  ExplodedNodeImpl* generateNodeImpl(const Destination& D, void* State,
+                                     bool isSink);
+  
+  inline Expr* getTarget() const { return E; }
+  inline void* getState() const { return Pred->State; }
+};
+  
+template<typename CHECKER>
+class GRIndirectGotoNodeBuilder {
+  typedef CHECKER                                CheckerTy; 
+  typedef typename CheckerTy::StateTy            StateTy;
+  typedef ExplodedGraph<CheckerTy>               GraphTy;
+  typedef typename GraphTy::NodeTy               NodeTy;
+
+  GRIndirectGotoNodeBuilderImpl& NB;
+
+public:
+  GRIndirectGotoNodeBuilder(GRIndirectGotoNodeBuilderImpl& nb) : NB(nb) {}
+  
+  typedef GRIndirectGotoNodeBuilderImpl::Iterator     iterator;
+  typedef GRIndirectGotoNodeBuilderImpl::Destination  Destination;
+
+  inline iterator begin() { return NB.begin(); }
+  inline iterator end() { return NB.end(); }
+  
+  inline Expr* getTarget() const { return NB.getTarget(); }
+  
+  inline NodeTy* generateNode(const Destination& D, StateTy St,
+                              bool isSink = false) {
+    
+    void *state = GRTrait<StateTy>::toPtr(St);        
+    return static_cast<NodeTy*>(NB.generateNodeImpl(D, state, isSink));
+  }
+  
+  inline StateTy getState() const {
+    return GRTrait<StateTy>::toState(NB.getState());
+  }    
+};
+
   
 template<typename CHECKER>
 class GREngine : public GREngineImpl {
@@ -274,13 +359,16 @@ protected:
     Checker->ProcessStmt(S, Builder);
   }
 
-
   virtual void ProcessBranch(Expr* Condition, Stmt* Terminator,
                              GRBranchNodeBuilderImpl& BuilderImpl) {
     GRBranchNodeBuilder<CHECKER> Builder(BuilderImpl);
     Checker->ProcessBranch(Condition, Terminator, Builder);    
   }
   
+  virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& BuilderImpl) {
+    GRIndirectGotoNodeBuilder<CHECKER> Builder(BuilderImpl);
+    Checker->ProcessIndirectGoto(Builder);
+  }
   
 public:  
   /// Construct a GREngine object to analyze the provided CFG using
index 39ce03fd968466a36a512306dcf22829fff16227..45ec936e9ab7c75937832a91533e261d85604723 100644 (file)
@@ -104,6 +104,15 @@ class BlockEdge : public ProgramPoint {
   typedef std::pair<CFGBlock*,CFGBlock*> BPair;
 public:
   BlockEdge(CFG& cfg, const CFGBlock* B1, const CFGBlock* B2);
+  
+  /// This ctor forces the BlockEdge to be constructed using an explicitly
+  ///  allocated pair object that is stored in the CFG.  This is usually
+  ///  used to construct edges representing jumps using computed gotos.
+  BlockEdge(CFG& cfg, const CFGBlock* B1, const CFGBlock* B2, bool) {
+    Data = reinterpret_cast<uintptr_t>(cfg.getBlockEdgeImpl(B1, B2))
+           | BlockEdgeAuxKind;
+  }
+
 
   CFGBlock* getSrc() const;
   CFGBlock* getDst() const;