From: Ted Kremenek Date: Wed, 13 Feb 2008 00:24:44 +0000 (+0000) Subject: Added support to GREngine/GRConstants for handling computed gotos. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=754607e7cff2d902d9af8b771409449fb2f8d2bf;p=clang Added support to GREngine/GRConstants for handling computed gotos. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@47038 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Analysis/GRConstants.cpp b/Analysis/GRConstants.cpp index 86ac5ef1aa..c2395512c5 100644 --- a/Analysis/GRConstants.cpp +++ b/Analysis/GRConstants.cpp @@ -67,6 +67,7 @@ public: typedef ValueStateManager::StateTy StateTy; typedef GRStmtNodeBuilder StmtNodeBuilder; typedef GRBranchNodeBuilder BranchNodeBuilder; + typedef GRIndirectGotoNodeBuilder IndirectGotoNodeBuilder; typedef ExplodedGraph 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(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(V)) { + LabelStmt* L = cast(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(V) || isa(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(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 : Out << "\\|Terminator: "; E.getSrc()->printTerminator(Out); - if (isa(T)) { + if (isa(T) || isa(T)) { // FIXME } else { diff --git a/Analysis/GREngine.cpp b/Analysis/GREngine.cpp index e7720d97a3..acce008cea 100644 --- a/Analysis/GREngine.cpp +++ b/Analysis/GREngine.cpp @@ -198,6 +198,18 @@ void GREngineImpl::HandleBlockExit(CFGBlock * B, ExplodedNodeImpl* Pred) { case Stmt::IfStmtClass: HandleBranch(cast(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(Term)->getTarget(), + *(B->succ_begin()), this); + + ProcessIndirectGoto(builder); + return; + } case Stmt::WhileStmtClass: HandleBranch(cast(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(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; +} diff --git a/include/clang/Analysis/PathSensitive/ExplodedGraph.h b/include/clang/Analysis/PathSensitive/ExplodedGraph.h index dcc833c0df..7b52003c6b 100644 --- a/include/clang/Analysis/PathSensitive/ExplodedGraph.h +++ b/include/clang/Analysis/PathSensitive/ExplodedGraph.h @@ -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 EdgeNodeSetMap; diff --git a/include/clang/Analysis/PathSensitive/GREngine.h b/include/clang/Analysis/PathSensitive/GREngine.h index 14ca1842da..4e1f2095cb 100644 --- a/include/clang/Analysis/PathSensitive/GREngine.h +++ b/include/clang/Analysis/PathSensitive/GREngine.h @@ -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 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 +class GRIndirectGotoNodeBuilder { + typedef CHECKER CheckerTy; + typedef typename CheckerTy::StateTy StateTy; + typedef ExplodedGraph 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::toPtr(St); + return static_cast(NB.generateNodeImpl(D, state, isSink)); + } + + inline StateTy getState() const { + return GRTrait::toState(NB.getState()); + } +}; + template class GREngine : public GREngineImpl { @@ -274,13 +359,16 @@ protected: Checker->ProcessStmt(S, Builder); } - virtual void ProcessBranch(Expr* Condition, Stmt* Terminator, GRBranchNodeBuilderImpl& BuilderImpl) { GRBranchNodeBuilder Builder(BuilderImpl); Checker->ProcessBranch(Condition, Terminator, Builder); } + virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilderImpl& BuilderImpl) { + GRIndirectGotoNodeBuilder Builder(BuilderImpl); + Checker->ProcessIndirectGoto(Builder); + } public: /// Construct a GREngine object to analyze the provided CFG using diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index 39ce03fd96..45ec936e9a 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -104,6 +104,15 @@ class BlockEdge : public ProgramPoint { typedef std::pair 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(cfg.getBlockEdgeImpl(B1, B2)) + | BlockEdgeAuxKind; + } + CFGBlock* getSrc() const; CFGBlock* getDst() const;