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 "llvm/ADT/OwningPtr.h"
26 class ProgramPointTag;
30 //===----------------------------------------------------------------------===//
31 /// CoreEngine - Implements the core logic of the graph-reachability
32 /// analysis. It traverses the CFG and generates the ExplodedGraph.
33 /// Program "states" are treated as opaque void pointers.
34 /// The template class CoreEngine (which subclasses CoreEngine)
35 /// provides the matching component to the engine that knows the actual types
36 /// for states. Note that this engine only dispatches to transfer functions
37 /// at the statement and block-level. The analyses themselves must implement
38 /// any transfer function logic and the sub-expression level (if any).
40 friend class StmtNodeBuilder;
41 friend class GenericNodeBuilderImpl;
42 friend class BranchNodeBuilder;
43 friend class IndirectGotoNodeBuilder;
44 friend class SwitchNodeBuilder;
45 friend class EndOfFunctionNodeBuilder;
46 friend class CallEnterNodeBuilder;
47 friend class CallExitNodeBuilder;
50 typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> >
53 typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> >
60 /// G - The simulation graph. Each node is a (location,state) pair.
61 llvm::OwningPtr<ExplodedGraph> G;
63 /// WList - A set of queued nodes that need to be processed by the
64 /// worklist algorithm. It is up to the implementation of WList to decide
65 /// the order that nodes are processed.
68 /// BCounterFactory - A factory object for created BlockCounter objects.
69 /// These are used to record for key nodes in the ExplodedGraph the
70 /// number of times different CFGBlocks have been visited along a path.
71 BlockCounter::Factory BCounterFactory;
73 /// The locations where we stopped doing work because we visited a location
75 BlocksExhausted blocksExhausted;
77 /// The locations where we stopped because the engine aborted analysis,
78 /// usually because it could not reason about something.
79 BlocksAborted blocksAborted;
81 void generateNode(const ProgramPoint &Loc,
82 const ProgramState *State,
85 void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred);
86 void HandleBlockEntrance(const BlockEntrance &E, ExplodedNode *Pred);
87 void HandleBlockExit(const CFGBlock *B, ExplodedNode *Pred);
88 void HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred);
90 void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B,
92 void HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
93 unsigned Index, ExplodedNode *Pred);
94 void HandleCallExit(const CallExit &L, ExplodedNode *Pred);
97 CoreEngine(const CoreEngine&); // Do not implement.
98 CoreEngine& operator=(const CoreEngine&);
101 /// Construct a CoreEngine object to analyze the provided CFG using
102 /// a DFS exploration of the exploded graph.
103 CoreEngine(SubEngine& subengine)
104 : SubEng(subengine), G(new ExplodedGraph()),
105 WList(WorkList::makeBFS()),
106 BCounterFactory(G->getAllocator()) {}
108 /// Construct a CoreEngine object to analyze the provided CFG and to
109 /// use the provided worklist object to execute the worklist algorithm.
110 /// The CoreEngine object assumes ownership of 'wlist'.
111 CoreEngine(WorkList* wlist, SubEngine& subengine)
112 : SubEng(subengine), G(new ExplodedGraph()), WList(wlist),
113 BCounterFactory(G->getAllocator()) {}
119 /// getGraph - Returns the exploded graph.
120 ExplodedGraph& getGraph() { return *G.get(); }
122 /// takeGraph - Returns the exploded graph. Ownership of the graph is
123 /// transferred to the caller.
124 ExplodedGraph* takeGraph() { return G.take(); }
126 /// ExecuteWorkList - Run the worklist algorithm for a maximum number of
127 /// steps. Returns true if there is still simulation state on the worklist.
128 bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
129 const ProgramState *InitState);
130 void ExecuteWorkListWithInitialState(const LocationContext *L,
132 const ProgramState *InitState,
133 ExplodedNodeSet &Dst);
135 // Functions for external checking of whether we have unfinished work
136 bool wasBlockAborted() const { return !blocksAborted.empty(); }
137 bool wasBlocksExhausted() const { return !blocksExhausted.empty(); }
138 bool hasWorkRemaining() const { return wasBlocksExhausted() ||
142 /// Inform the CoreEngine that a basic block was aborted because
143 /// it could not be completely analyzed.
144 void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) {
145 blocksAborted.push_back(std::make_pair(block, node));
148 WorkList *getWorkList() const { return WList; }
150 BlocksExhausted::const_iterator blocks_exhausted_begin() const {
151 return blocksExhausted.begin();
153 BlocksExhausted::const_iterator blocks_exhausted_end() const {
154 return blocksExhausted.end();
156 BlocksAborted::const_iterator blocks_aborted_begin() const {
157 return blocksAborted.begin();
159 BlocksAborted::const_iterator blocks_aborted_end() const {
160 return blocksAborted.end();
164 class StmtNodeBuilder {
172 bool PurgingDeadSymbols;
174 bool hasGeneratedNode;
175 ProgramPoint::Kind PointKind;
176 const ProgramPointTag *Tag;
178 typedef llvm::SmallPtrSet<ExplodedNode*,5> DeferredTy;
181 void GenerateAutoTransition(ExplodedNode *N);
184 StmtNodeBuilder(const CFGBlock *b,
191 ExplodedNode *getPredecessor() const { return Pred; }
193 // FIXME: This should not be exposed.
194 WorkList *getWorkList() { return Eng.WList; }
196 BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
198 unsigned getCurrentBlockCount() const {
199 return getBlockCounter().getNumVisited(
200 Pred->getLocationContext()->getCurrentStackFrame(),
204 ExplodedNode *generateNode(const Stmt *S,
205 const ProgramState *St,
207 ProgramPoint::Kind K,
208 const ProgramPointTag *tag = 0) {
209 hasGeneratedNode = true;
211 if (PurgingDeadSymbols)
212 K = ProgramPoint::PostPurgeDeadSymbolsKind;
214 return generateNodeInternal(S, St, Pred, K, tag ? tag : Tag);
217 ExplodedNode *generateNode(const Stmt *S,
218 const ProgramState *St,
220 const ProgramPointTag *tag = 0) {
221 return generateNode(S, St, Pred, PointKind, tag);
224 ExplodedNode *generateNode(const ProgramPoint &PP,
225 const ProgramState *State,
226 ExplodedNode *Pred) {
227 hasGeneratedNode = true;
228 return generateNodeInternal(PP, State, Pred);
232 generateNodeInternal(const ProgramPoint &PP,
233 const ProgramState *State,
237 generateNodeInternal(const Stmt *S,
238 const ProgramState *State,
240 ProgramPoint::Kind K,
241 const ProgramPointTag *tag = 0);
243 /// getStmt - Return the current block-level expression associated with
245 const Stmt *getStmt() const {
246 const CFGStmt *CS = B[Idx].getAs<CFGStmt>();
247 return CS ? CS->getStmt() : 0;
250 /// getBlock - Return the CFGBlock associated with the block-level expression
252 const CFGBlock *getBlock() const { return &B; }
254 unsigned getIndex() const { return Idx; }
256 ExplodedNode *MakeNode(ExplodedNodeSet &Dst,
259 const ProgramState *St) {
260 return MakeNode(Dst, S, Pred, St, PointKind);
263 ExplodedNode *MakeNode(ExplodedNodeSet &Dst,
266 const ProgramState *St,
267 ProgramPoint::Kind K);
269 ExplodedNode *MakeSinkNode(ExplodedNodeSet &Dst,
272 const ProgramState *St) {
273 bool Tmp = BuildSinks;
275 ExplodedNode *N = MakeNode(Dst, S, Pred, St);
281 class BranchNodeBuilder {
284 const CFGBlock *DstT;
285 const CFGBlock *DstF;
288 typedef SmallVector<ExplodedNode*,3> DeferredTy;
294 bool InFeasibleFalse;
297 BranchNodeBuilder(const CFGBlock *src, const CFGBlock *dstT,
298 const CFGBlock *dstF, ExplodedNode *pred, CoreEngine* e)
299 : Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred),
300 GeneratedTrue(false), GeneratedFalse(false),
301 InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {}
303 ~BranchNodeBuilder();
305 ExplodedNode *getPredecessor() const { return Pred; }
307 const ExplodedGraph& getGraph() const { return *Eng.G; }
309 BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
311 /// This function generates a new ExplodedNode but not a new
312 /// branch(block edge).
313 ExplodedNode *generateNode(const Stmt *Condition, const ProgramState *State);
315 ExplodedNode *generateNode(const ProgramState *State, bool branch);
317 const CFGBlock *getTargetBlock(bool branch) const {
318 return branch ? DstT : DstF;
321 void markInfeasible(bool branch) {
323 InFeasibleTrue = GeneratedTrue = true;
325 InFeasibleFalse = GeneratedFalse = true;
328 bool isFeasible(bool branch) {
329 return branch ? !InFeasibleTrue : !InFeasibleFalse;
332 const ProgramState *getState() const {
333 return getPredecessor()->getState();
337 class IndirectGotoNodeBuilder {
340 const CFGBlock &DispatchBlock;
345 IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
346 const Expr *e, const CFGBlock *dispatch, CoreEngine* eng)
347 : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
350 CFGBlock::const_succ_iterator I;
352 friend class IndirectGotoNodeBuilder;
353 iterator(CFGBlock::const_succ_iterator i) : I(i) {}
356 iterator &operator++() { ++I; return *this; }
357 bool operator!=(const iterator &X) const { return I != X.I; }
359 const LabelDecl *getLabel() const {
360 return llvm::cast<LabelStmt>((*I)->getLabel())->getDecl();
363 const CFGBlock *getBlock() const {
368 iterator begin() { return iterator(DispatchBlock.succ_begin()); }
369 iterator end() { return iterator(DispatchBlock.succ_end()); }
371 ExplodedNode *generateNode(const iterator &I,
372 const ProgramState *State,
373 bool isSink = false);
375 const Expr *getTarget() const { return E; }
377 const ProgramState *getState() const { return Pred->State; }
380 class SwitchNodeBuilder {
383 const Expr *Condition;
387 SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
388 const Expr *condition, CoreEngine* eng)
389 : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
392 CFGBlock::const_succ_reverse_iterator I;
394 friend class SwitchNodeBuilder;
395 iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {}
398 iterator &operator++() { ++I; return *this; }
399 bool operator!=(const iterator &X) const { return I != X.I; }
400 bool operator==(const iterator &X) const { return I == X.I; }
402 const CaseStmt *getCase() const {
403 return llvm::cast<CaseStmt>((*I)->getLabel());
406 const CFGBlock *getBlock() const {
411 iterator begin() { return iterator(Src->succ_rbegin()+1); }
412 iterator end() { return iterator(Src->succ_rend()); }
414 const SwitchStmt *getSwitch() const {
415 return llvm::cast<SwitchStmt>(Src->getTerminator());
418 ExplodedNode *generateCaseStmtNode(const iterator &I,
419 const ProgramState *State);
421 ExplodedNode *generateDefaultCaseNode(const ProgramState *State,
422 bool isSink = false);
424 const Expr *getCondition() const { return Condition; }
426 const ProgramState *getState() const { return Pred->State; }
429 class GenericNodeBuilderImpl {
434 SmallVector<ExplodedNode*, 2> sinksGenerated;
436 ExplodedNode *generateNodeImpl(const ProgramState *state,
438 ProgramPoint programPoint,
441 GenericNodeBuilderImpl(CoreEngine &eng, ExplodedNode *pr, ProgramPoint p)
442 : engine(eng), pred(pr), pp(p), hasGeneratedNode(false) {}
445 bool hasGeneratedNode;
447 WorkList &getWorkList() { return *engine.WList; }
449 ExplodedNode *getPredecessor() const { return pred; }
451 BlockCounter getBlockCounter() const {
452 return engine.WList->getBlockCounter();
455 const SmallVectorImpl<ExplodedNode*> &sinks() const {
456 return sinksGenerated;
460 template <typename PP_T>
461 class GenericNodeBuilder : public GenericNodeBuilderImpl {
463 GenericNodeBuilder(CoreEngine &eng, ExplodedNode *pr, const PP_T &p)
464 : GenericNodeBuilderImpl(eng, pr, p) {}
466 ExplodedNode *generateNode(const ProgramState *state, ExplodedNode *pred,
467 const ProgramPointTag *tag, bool asSink) {
468 return generateNodeImpl(state, pred, cast<PP_T>(pp).withTag(tag),
472 const PP_T &getProgramPoint() const { return cast<PP_T>(pp); }
475 class EndOfFunctionNodeBuilder {
479 const ProgramPointTag *Tag;
482 bool hasGeneratedNode;
485 EndOfFunctionNodeBuilder(const CFGBlock *b, ExplodedNode *N, CoreEngine* e,
486 const ProgramPointTag *tag = 0)
487 : Eng(*e), B(*b), Pred(N), Tag(tag), hasGeneratedNode(false) {}
489 ~EndOfFunctionNodeBuilder();
491 EndOfFunctionNodeBuilder withCheckerTag(const ProgramPointTag *tag) {
492 return EndOfFunctionNodeBuilder(&B, Pred, &Eng, tag);
495 WorkList &getWorkList() { return *Eng.WList; }
497 ExplodedNode *getPredecessor() const { return Pred; }
499 BlockCounter getBlockCounter() const {
500 return Eng.WList->getBlockCounter();
503 unsigned getCurrentBlockCount() const {
504 return getBlockCounter().getNumVisited(
505 Pred->getLocationContext()->getCurrentStackFrame(),
509 ExplodedNode *generateNode(const ProgramState *State,
511 const ProgramPointTag *tag = 0);
513 void GenerateCallExitNode(const ProgramState *state);
515 const CFGBlock *getBlock() const { return &B; }
517 const ProgramState *getState() const {
518 return getPredecessor()->getState();
522 class CallEnterNodeBuilder {
525 const ExplodedNode *Pred;
527 // The call site. For implicit automatic object dtor, this is the trigger
531 // The context of the callee.
532 const StackFrameContext *CalleeCtx;
534 // The parent block of the CallExpr.
535 const CFGBlock *Block;
537 // The CFGBlock index of the CallExpr.
541 CallEnterNodeBuilder(CoreEngine &eng, const ExplodedNode *pred,
542 const Stmt *s, const StackFrameContext *callee,
543 const CFGBlock *blk, unsigned idx)
544 : Eng(eng), Pred(pred), CE(s), CalleeCtx(callee), Block(blk), Index(idx) {}
546 const ProgramState *getState() const { return Pred->getState(); }
548 const LocationContext *getLocationContext() const {
549 return Pred->getLocationContext();
552 const Stmt *getCallExpr() const { return CE; }
554 const StackFrameContext *getCalleeContext() const { return CalleeCtx; }
556 const CFGBlock *getBlock() const { return Block; }
558 unsigned getIndex() const { return Index; }
560 void generateNode(const ProgramState *state);
563 class CallExitNodeBuilder {
565 const ExplodedNode *Pred;
568 CallExitNodeBuilder(CoreEngine &eng, const ExplodedNode *pred)
569 : Eng(eng), Pred(pred) {}
571 const ExplodedNode *getPredecessor() const { return Pred; }
573 const ProgramState *getState() const { return Pred->getState(); }
575 void generateNode(const ProgramState *state);
578 } // end GR namespace
580 } // end clang namespace