1 //==- CoreEngine.h - Path-Sensitive Dataflow Engine ----------------*- C++ -*-//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines a generic engine for intraprocedural, path-sensitive,
11 // dataflow analysis via graph reachability.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_CLANG_GR_COREENGINE
16 #define LLVM_CLANG_GR_COREENGINE
18 #include "clang/AST/Expr.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
23 #include "llvm/ADT/OwningPtr.h"
29 //===----------------------------------------------------------------------===//
30 /// CoreEngine - Implements the core logic of the graph-reachability
31 /// analysis. It traverses the CFG and generates the ExplodedGraph.
32 /// Program "states" are treated as opaque void pointers.
33 /// The template class CoreEngine (which subclasses CoreEngine)
34 /// provides the matching component to the engine that knows the actual types
35 /// for states. Note that this engine only dispatches to transfer functions
36 /// at the statement and block-level. The analyses themselves must implement
37 /// any transfer function logic and the sub-expression level (if any).
39 friend class StmtNodeBuilder;
40 friend class GenericNodeBuilderImpl;
41 friend class BranchNodeBuilder;
42 friend class IndirectGotoNodeBuilder;
43 friend class SwitchNodeBuilder;
44 friend class EndOfFunctionNodeBuilder;
45 friend class CallEnterNodeBuilder;
46 friend class CallExitNodeBuilder;
49 typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> >
52 typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> >
59 /// G - The simulation graph. Each node is a (location,state) pair.
60 llvm::OwningPtr<ExplodedGraph> G;
62 /// WList - A set of queued nodes that need to be processed by the
63 /// worklist algorithm. It is up to the implementation of WList to decide
64 /// the order that nodes are processed.
67 /// BCounterFactory - A factory object for created BlockCounter objects.
68 /// These are used to record for key nodes in the ExplodedGraph the
69 /// number of times different CFGBlocks have been visited along a path.
70 BlockCounter::Factory BCounterFactory;
72 /// The locations where we stopped doing work because we visited a location
74 BlocksExhausted blocksExhausted;
76 /// The locations where we stopped because the engine aborted analysis,
77 /// usually because it could not reason about something.
78 BlocksAborted blocksAborted;
80 void generateNode(const ProgramPoint& Loc, const GRState* State,
83 void HandleBlockEdge(const BlockEdge& E, ExplodedNode* Pred);
84 void HandleBlockEntrance(const BlockEntrance& E, ExplodedNode* Pred);
85 void HandleBlockExit(const CFGBlock* B, ExplodedNode* Pred);
86 void HandlePostStmt(const CFGBlock* B, unsigned StmtIdx, ExplodedNode *Pred);
88 void HandleBranch(const Stmt* Cond, const Stmt* Term, const CFGBlock* B,
90 void HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
91 unsigned Index, ExplodedNode *Pred);
92 void HandleCallExit(const CallExit &L, ExplodedNode *Pred);
95 CoreEngine(const CoreEngine&); // Do not implement.
96 CoreEngine& operator=(const CoreEngine&);
99 /// Construct a CoreEngine object to analyze the provided CFG using
100 /// a DFS exploration of the exploded graph.
101 CoreEngine(SubEngine& subengine)
102 : SubEng(subengine), G(new ExplodedGraph()),
103 WList(WorkList::makeBFS()),
104 BCounterFactory(G->getAllocator()) {}
106 /// Construct a CoreEngine object to analyze the provided CFG and to
107 /// use the provided worklist object to execute the worklist algorithm.
108 /// The CoreEngine object assumes ownership of 'wlist'.
109 CoreEngine(WorkList* wlist, SubEngine& subengine)
110 : SubEng(subengine), G(new ExplodedGraph()), WList(wlist),
111 BCounterFactory(G->getAllocator()) {}
117 /// getGraph - Returns the exploded graph.
118 ExplodedGraph& getGraph() { return *G.get(); }
120 /// takeGraph - Returns the exploded graph. Ownership of the graph is
121 /// transferred to the caller.
122 ExplodedGraph* takeGraph() { return G.take(); }
124 /// ExecuteWorkList - Run the worklist algorithm for a maximum number of
125 /// steps. Returns true if there is still simulation state on the worklist.
126 bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
127 const GRState *InitState);
128 void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
129 const GRState *InitState,
130 ExplodedNodeSet &Dst);
132 // Functions for external checking of whether we have unfinished work
133 bool wasBlockAborted() const { return !blocksAborted.empty(); }
134 bool wasBlocksExhausted() const { return !blocksExhausted.empty(); }
135 bool hasWorkRemaining() const { return wasBlocksExhausted() ||
139 /// Inform the CoreEngine that a basic block was aborted because
140 /// it could not be completely analyzed.
141 void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) {
142 blocksAborted.push_back(std::make_pair(block, node));
145 WorkList *getWorkList() const { return WList; }
147 BlocksExhausted::const_iterator blocks_exhausted_begin() const {
148 return blocksExhausted.begin();
150 BlocksExhausted::const_iterator blocks_exhausted_end() const {
151 return blocksExhausted.end();
153 BlocksAborted::const_iterator blocks_aborted_begin() const {
154 return blocksAborted.begin();
156 BlocksAborted::const_iterator blocks_aborted_end() const {
157 return blocksAborted.end();
161 class StmtNodeBuilder {
169 bool PurgingDeadSymbols;
171 bool hasGeneratedNode;
172 ProgramPoint::Kind PointKind;
175 const GRState* CleanedState;
178 typedef llvm::SmallPtrSet<ExplodedNode*,5> DeferredTy;
181 void GenerateAutoTransition(ExplodedNode* N);
184 StmtNodeBuilder(const CFGBlock* b, unsigned idx, ExplodedNode* N,
185 CoreEngine* e, GRStateManager &mgr);
189 ExplodedNode* getPredecessor() const { return Pred; }
191 // FIXME: This should not be exposed.
192 WorkList *getWorkList() { return Eng.WList; }
194 void SetCleanedState(const GRState* St) {
198 BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
200 unsigned getCurrentBlockCount() const {
201 return getBlockCounter().getNumVisited(
202 Pred->getLocationContext()->getCurrentStackFrame(),
206 ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) {
207 hasGeneratedNode = true;
208 return generateNodeInternal(PP, St, Pred);
211 ExplodedNode* generateNode(const Stmt *S, const GRState *St,
212 ExplodedNode *Pred, ProgramPoint::Kind K,
213 const void *tag = 0) {
214 hasGeneratedNode = true;
216 if (PurgingDeadSymbols)
217 K = ProgramPoint::PostPurgeDeadSymbolsKind;
219 return generateNodeInternal(S, St, Pred, K, tag ? tag : Tag);
222 ExplodedNode* generateNode(const Stmt *S, const GRState *St,
223 ExplodedNode *Pred, const void *tag = 0) {
224 return generateNode(S, St, Pred, PointKind, tag);
227 ExplodedNode *generateNode(const ProgramPoint &PP, const GRState* State,
228 ExplodedNode* Pred) {
229 hasGeneratedNode = true;
230 return generateNodeInternal(PP, State, Pred);
234 generateNodeInternal(const ProgramPoint &PP, const GRState* State,
238 generateNodeInternal(const Stmt* S, const GRState* State, ExplodedNode* Pred,
239 ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
240 const void *tag = 0);
242 /// getStmt - Return the current block-level expression associated with
244 const Stmt* getStmt() const {
245 const CFGStmt *CS = B[Idx].getAs<CFGStmt>();
246 return CS ? CS->getStmt() : 0;
249 /// getBlock - Return the CFGBlock associated with the block-level expression
251 const CFGBlock* getBlock() const { return &B; }
253 unsigned getIndex() const { return Idx; }
255 const GRState* GetState(ExplodedNode* Pred) const {
256 if (Pred == getPredecessor())
259 return Pred->getState();
262 ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
263 ExplodedNode* Pred, const GRState* St) {
264 return MakeNode(Dst, S, Pred, St, PointKind);
267 ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S,ExplodedNode* Pred,
268 const GRState* St, ProgramPoint::Kind K);
270 ExplodedNode* MakeSinkNode(ExplodedNodeSet& Dst, const Stmt* S,
271 ExplodedNode* Pred, const GRState* St) {
272 bool Tmp = BuildSinks;
274 ExplodedNode* N = MakeNode(Dst, S, Pred, St);
280 class BranchNodeBuilder {
283 const CFGBlock* DstT;
284 const CFGBlock* DstF;
287 typedef llvm::SmallVector<ExplodedNode*,3> DeferredTy;
293 bool InFeasibleFalse;
296 BranchNodeBuilder(const CFGBlock* src, const CFGBlock* dstT,
297 const CFGBlock* dstF, ExplodedNode* pred, CoreEngine* e)
298 : Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred),
299 GeneratedTrue(false), GeneratedFalse(false),
300 InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {}
302 ~BranchNodeBuilder();
304 ExplodedNode* getPredecessor() const { return Pred; }
306 const ExplodedGraph& getGraph() const { return *Eng.G; }
308 BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
310 ExplodedNode* generateNode(const Stmt *Condition, const GRState* State);
312 ExplodedNode* generateNode(const GRState* State, bool branch);
314 const CFGBlock* getTargetBlock(bool branch) const {
315 return branch ? DstT : DstF;
318 void markInfeasible(bool branch) {
320 InFeasibleTrue = GeneratedTrue = true;
322 InFeasibleFalse = GeneratedFalse = true;
325 bool isFeasible(bool branch) {
326 return branch ? !InFeasibleTrue : !InFeasibleFalse;
329 const GRState* getState() const {
330 return getPredecessor()->getState();
334 class IndirectGotoNodeBuilder {
337 const CFGBlock& DispatchBlock;
342 IndirectGotoNodeBuilder(ExplodedNode* pred, const CFGBlock* src,
343 const Expr* e, const CFGBlock* dispatch, CoreEngine* eng)
344 : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
347 CFGBlock::const_succ_iterator I;
349 friend class IndirectGotoNodeBuilder;
350 iterator(CFGBlock::const_succ_iterator i) : I(i) {}
353 iterator& operator++() { ++I; return *this; }
354 bool operator!=(const iterator& X) const { return I != X.I; }
356 const LabelDecl *getLabel() const {
357 return llvm::cast<LabelStmt>((*I)->getLabel())->getDecl();
360 const CFGBlock *getBlock() const {
365 iterator begin() { return iterator(DispatchBlock.succ_begin()); }
366 iterator end() { return iterator(DispatchBlock.succ_end()); }
368 ExplodedNode* generateNode(const iterator& I, const GRState* State,
369 bool isSink = false);
371 const Expr* getTarget() const { return E; }
373 const GRState* getState() const { return Pred->State; }
376 class SwitchNodeBuilder {
379 const Expr* Condition;
383 SwitchNodeBuilder(ExplodedNode* pred, const CFGBlock* src,
384 const Expr* condition, CoreEngine* eng)
385 : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
388 CFGBlock::const_succ_reverse_iterator I;
390 friend class SwitchNodeBuilder;
391 iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {}
394 iterator& operator++() { ++I; return *this; }
395 bool operator!=(const iterator &X) const { return I != X.I; }
396 bool operator==(const iterator &X) const { return I == X.I; }
398 const CaseStmt* getCase() const {
399 return llvm::cast<CaseStmt>((*I)->getLabel());
402 const CFGBlock* getBlock() const {
407 iterator begin() { return iterator(Src->succ_rbegin()+1); }
408 iterator end() { return iterator(Src->succ_rend()); }
410 const SwitchStmt *getSwitch() const {
411 return llvm::cast<SwitchStmt>(Src->getTerminator());
414 ExplodedNode* generateCaseStmtNode(const iterator& I, const GRState* State);
416 ExplodedNode* generateDefaultCaseNode(const GRState* State,
417 bool isSink = false);
419 const Expr* getCondition() const { return Condition; }
421 const GRState* getState() const { return Pred->State; }
424 class GenericNodeBuilderImpl {
429 llvm::SmallVector<ExplodedNode*, 2> sinksGenerated;
431 ExplodedNode *generateNodeImpl(const GRState *state, ExplodedNode *pred,
432 ProgramPoint programPoint, bool asSink);
434 GenericNodeBuilderImpl(CoreEngine &eng, ExplodedNode *pr, ProgramPoint p)
435 : engine(eng), pred(pr), pp(p), hasGeneratedNode(false) {}
438 bool hasGeneratedNode;
440 WorkList &getWorkList() { return *engine.WList; }
442 ExplodedNode* getPredecessor() const { return pred; }
444 BlockCounter getBlockCounter() const {
445 return engine.WList->getBlockCounter();
448 const llvm::SmallVectorImpl<ExplodedNode*> &sinks() const {
449 return sinksGenerated;
453 template <typename PP_T>
454 class GenericNodeBuilder : public GenericNodeBuilderImpl {
456 GenericNodeBuilder(CoreEngine &eng, ExplodedNode *pr, const PP_T &p)
457 : GenericNodeBuilderImpl(eng, pr, p) {}
459 ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred,
460 const void *tag, bool asSink) {
461 return generateNodeImpl(state, pred, cast<PP_T>(pp).withTag(tag),
465 const PP_T &getProgramPoint() const { return cast<PP_T>(pp); }
468 class EndOfFunctionNodeBuilder {
475 bool hasGeneratedNode;
478 EndOfFunctionNodeBuilder(const CFGBlock* b, ExplodedNode* N, CoreEngine* e,
479 void *checkerTag = 0)
480 : Eng(*e), B(*b), Pred(N), Tag(checkerTag), hasGeneratedNode(false) {}
482 ~EndOfFunctionNodeBuilder();
484 EndOfFunctionNodeBuilder withCheckerTag(void *tag) {
485 return EndOfFunctionNodeBuilder(&B, Pred, &Eng, tag);
488 WorkList &getWorkList() { return *Eng.WList; }
490 ExplodedNode* getPredecessor() const { return Pred; }
492 BlockCounter getBlockCounter() const {
493 return Eng.WList->getBlockCounter();
496 unsigned getCurrentBlockCount() const {
497 return getBlockCounter().getNumVisited(
498 Pred->getLocationContext()->getCurrentStackFrame(),
502 ExplodedNode* generateNode(const GRState* State, ExplodedNode *P = 0,
503 const void *tag = 0);
505 void GenerateCallExitNode(const GRState *state);
507 const CFGBlock* getBlock() const { return &B; }
509 const GRState* getState() const {
510 return getPredecessor()->getState();
514 class CallEnterNodeBuilder {
517 const ExplodedNode *Pred;
519 // The call site. For implicit automatic object dtor, this is the trigger
523 // The context of the callee.
524 const StackFrameContext *CalleeCtx;
526 // The parent block of the CallExpr.
527 const CFGBlock *Block;
529 // The CFGBlock index of the CallExpr.
533 CallEnterNodeBuilder(CoreEngine &eng, const ExplodedNode *pred,
534 const Stmt *s, const StackFrameContext *callee,
535 const CFGBlock *blk, unsigned idx)
536 : Eng(eng), Pred(pred), CE(s), CalleeCtx(callee), Block(blk), Index(idx) {}
538 const GRState *getState() const { return Pred->getState(); }
540 const LocationContext *getLocationContext() const {
541 return Pred->getLocationContext();
544 const Stmt *getCallExpr() const { return CE; }
546 const StackFrameContext *getCalleeContext() const { return CalleeCtx; }
548 const CFGBlock *getBlock() const { return Block; }
550 unsigned getIndex() const { return Index; }
552 void generateNode(const GRState *state);
555 class CallExitNodeBuilder {
557 const ExplodedNode *Pred;
560 CallExitNodeBuilder(CoreEngine &eng, const ExplodedNode *pred)
561 : Eng(eng), Pred(pred) {}
563 const ExplodedNode *getPredecessor() const { return Pred; }
565 const GRState *getState() const { return Pred->getState(); }
567 void generateNode(const GRState *state);
570 } // end GR namespace
572 } // end clang namespace