• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //==- CoreEngine.h - Path-Sensitive Dataflow Engine ----------------*- C++ -*-//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file defines a generic engine for intraprocedural, path-sensitive,
11 //  dataflow analysis via graph reachability.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CLANG_GR_COREENGINE
16 #define LLVM_CLANG_GR_COREENGINE
17 
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"
24 
25 namespace clang {
26 
27 namespace ento {
28 
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).
38 class CoreEngine {
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;
47 
48 public:
49   typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> >
50             BlocksExhausted;
51 
52   typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> >
53             BlocksAborted;
54 
55 private:
56 
57   SubEngine& SubEng;
58 
59   /// G - The simulation graph.  Each node is a (location,state) pair.
60   llvm::OwningPtr<ExplodedGraph> G;
61 
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.
65   WorkList* WList;
66 
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;
71 
72   /// The locations where we stopped doing work because we visited a location
73   ///  too many times.
74   BlocksExhausted blocksExhausted;
75 
76   /// The locations where we stopped because the engine aborted analysis,
77   /// usually because it could not reason about something.
78   BlocksAborted blocksAborted;
79 
80   void generateNode(const ProgramPoint& Loc, const GRState* State,
81                     ExplodedNode* Pred);
82 
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);
87 
88   void HandleBranch(const Stmt* Cond, const Stmt* Term, const CFGBlock* B,
89                     ExplodedNode* Pred);
90   void HandleCallEnter(const CallEnter &L, const CFGBlock *Block,
91                        unsigned Index, ExplodedNode *Pred);
92   void HandleCallExit(const CallExit &L, ExplodedNode *Pred);
93 
94 private:
95   CoreEngine(const CoreEngine&); // Do not implement.
96   CoreEngine& operator=(const CoreEngine&);
97 
98 public:
99   /// Construct a CoreEngine object to analyze the provided CFG using
100   ///  a DFS exploration of the exploded graph.
CoreEngine(SubEngine & subengine)101   CoreEngine(SubEngine& subengine)
102     : SubEng(subengine), G(new ExplodedGraph()),
103       WList(WorkList::makeBFS()),
104       BCounterFactory(G->getAllocator()) {}
105 
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'.
CoreEngine(WorkList * wlist,SubEngine & subengine)109   CoreEngine(WorkList* wlist, SubEngine& subengine)
110     : SubEng(subengine), G(new ExplodedGraph()), WList(wlist),
111       BCounterFactory(G->getAllocator()) {}
112 
~CoreEngine()113   ~CoreEngine() {
114     delete WList;
115   }
116 
117   /// getGraph - Returns the exploded graph.
getGraph()118   ExplodedGraph& getGraph() { return *G.get(); }
119 
120   /// takeGraph - Returns the exploded graph.  Ownership of the graph is
121   ///  transferred to the caller.
takeGraph()122   ExplodedGraph* takeGraph() { return G.take(); }
123 
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);
131 
132   // Functions for external checking of whether we have unfinished work
wasBlockAborted()133   bool wasBlockAborted() const { return !blocksAborted.empty(); }
wasBlocksExhausted()134   bool wasBlocksExhausted() const { return !blocksExhausted.empty(); }
hasWorkRemaining()135   bool hasWorkRemaining() const { return wasBlocksExhausted() ||
136                                          WList->hasWork() ||
137                                          wasBlockAborted(); }
138 
139   /// Inform the CoreEngine that a basic block was aborted because
140   /// it could not be completely analyzed.
addAbortedBlock(const ExplodedNode * node,const CFGBlock * block)141   void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) {
142     blocksAborted.push_back(std::make_pair(block, node));
143   }
144 
getWorkList()145   WorkList *getWorkList() const { return WList; }
146 
blocks_exhausted_begin()147   BlocksExhausted::const_iterator blocks_exhausted_begin() const {
148     return blocksExhausted.begin();
149   }
blocks_exhausted_end()150   BlocksExhausted::const_iterator blocks_exhausted_end() const {
151     return blocksExhausted.end();
152   }
blocks_aborted_begin()153   BlocksAborted::const_iterator blocks_aborted_begin() const {
154     return blocksAborted.begin();
155   }
blocks_aborted_end()156   BlocksAborted::const_iterator blocks_aborted_end() const {
157     return blocksAborted.end();
158   }
159 };
160 
161 class StmtNodeBuilder {
162   CoreEngine& Eng;
163   const CFGBlock& B;
164   const unsigned Idx;
165   ExplodedNode* Pred;
166   GRStateManager& Mgr;
167 
168 public:
169   bool PurgingDeadSymbols;
170   bool BuildSinks;
171   bool hasGeneratedNode;
172   ProgramPoint::Kind PointKind;
173   const void *Tag;
174 
175   const GRState* CleanedState;
176 
177 
178   typedef llvm::SmallPtrSet<ExplodedNode*,5> DeferredTy;
179   DeferredTy Deferred;
180 
181   void GenerateAutoTransition(ExplodedNode* N);
182 
183 public:
184   StmtNodeBuilder(const CFGBlock* b, unsigned idx, ExplodedNode* N,
185                     CoreEngine* e, GRStateManager &mgr);
186 
187   ~StmtNodeBuilder();
188 
getPredecessor()189   ExplodedNode* getPredecessor() const { return Pred; }
190 
191   // FIXME: This should not be exposed.
getWorkList()192   WorkList *getWorkList() { return Eng.WList; }
193 
SetCleanedState(const GRState * St)194   void SetCleanedState(const GRState* St) {
195     CleanedState = St;
196   }
197 
getBlockCounter()198   BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
199 
getCurrentBlockCount()200   unsigned getCurrentBlockCount() const {
201     return getBlockCounter().getNumVisited(
202                             Pred->getLocationContext()->getCurrentStackFrame(),
203                                            B.getBlockID());
204   }
205 
generateNode(PostStmt PP,const GRState * St,ExplodedNode * Pred)206   ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) {
207     hasGeneratedNode = true;
208     return generateNodeInternal(PP, St, Pred);
209   }
210 
211   ExplodedNode* generateNode(const Stmt *S, const GRState *St,
212                              ExplodedNode *Pred, ProgramPoint::Kind K,
213                              const void *tag = 0) {
214     hasGeneratedNode = true;
215 
216     if (PurgingDeadSymbols)
217       K = ProgramPoint::PostPurgeDeadSymbolsKind;
218 
219     return generateNodeInternal(S, St, Pred, K, tag ? tag : Tag);
220   }
221 
222   ExplodedNode* generateNode(const Stmt *S, const GRState *St,
223                              ExplodedNode *Pred, const void *tag = 0) {
224     return generateNode(S, St, Pred, PointKind, tag);
225   }
226 
generateNode(const ProgramPoint & PP,const GRState * State,ExplodedNode * Pred)227   ExplodedNode *generateNode(const ProgramPoint &PP, const GRState* State,
228                              ExplodedNode* Pred) {
229     hasGeneratedNode = true;
230     return generateNodeInternal(PP, State, Pred);
231   }
232 
233   ExplodedNode*
234   generateNodeInternal(const ProgramPoint &PP, const GRState* State,
235                        ExplodedNode* Pred);
236 
237   ExplodedNode*
238   generateNodeInternal(const Stmt* S, const GRState* State, ExplodedNode* Pred,
239                    ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
240                    const void *tag = 0);
241 
242   /// getStmt - Return the current block-level expression associated with
243   ///  this builder.
getStmt()244   const Stmt* getStmt() const {
245     const CFGStmt *CS = B[Idx].getAs<CFGStmt>();
246     return CS ? CS->getStmt() : 0;
247   }
248 
249   /// getBlock - Return the CFGBlock associated with the block-level expression
250   ///  of this builder.
getBlock()251   const CFGBlock* getBlock() const { return &B; }
252 
getIndex()253   unsigned getIndex() const { return Idx; }
254 
GetState(ExplodedNode * Pred)255   const GRState* GetState(ExplodedNode* Pred) const {
256     if (Pred == getPredecessor())
257       return CleanedState;
258     else
259       return Pred->getState();
260   }
261 
MakeNode(ExplodedNodeSet & Dst,const Stmt * S,ExplodedNode * Pred,const GRState * St)262   ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
263                          ExplodedNode* Pred, const GRState* St) {
264     return MakeNode(Dst, S, Pred, St, PointKind);
265   }
266 
267   ExplodedNode* MakeNode(ExplodedNodeSet& Dst, const Stmt* S,ExplodedNode* Pred,
268                          const GRState* St, ProgramPoint::Kind K);
269 
MakeSinkNode(ExplodedNodeSet & Dst,const Stmt * S,ExplodedNode * Pred,const GRState * St)270   ExplodedNode* MakeSinkNode(ExplodedNodeSet& Dst, const Stmt* S,
271                        ExplodedNode* Pred, const GRState* St) {
272     bool Tmp = BuildSinks;
273     BuildSinks = true;
274     ExplodedNode* N = MakeNode(Dst, S, Pred, St);
275     BuildSinks = Tmp;
276     return N;
277   }
278 };
279 
280 class BranchNodeBuilder {
281   CoreEngine& Eng;
282   const CFGBlock* Src;
283   const CFGBlock* DstT;
284   const CFGBlock* DstF;
285   ExplodedNode* Pred;
286 
287   typedef llvm::SmallVector<ExplodedNode*,3> DeferredTy;
288   DeferredTy Deferred;
289 
290   bool GeneratedTrue;
291   bool GeneratedFalse;
292   bool InFeasibleTrue;
293   bool InFeasibleFalse;
294 
295 public:
BranchNodeBuilder(const CFGBlock * src,const CFGBlock * dstT,const CFGBlock * dstF,ExplodedNode * pred,CoreEngine * e)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) {}
301 
302   ~BranchNodeBuilder();
303 
getPredecessor()304   ExplodedNode* getPredecessor() const { return Pred; }
305 
getGraph()306   const ExplodedGraph& getGraph() const { return *Eng.G; }
307 
getBlockCounter()308   BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
309 
310   ExplodedNode* generateNode(const Stmt *Condition, const GRState* State);
311 
312   ExplodedNode* generateNode(const GRState* State, bool branch);
313 
getTargetBlock(bool branch)314   const CFGBlock* getTargetBlock(bool branch) const {
315     return branch ? DstT : DstF;
316   }
317 
markInfeasible(bool branch)318   void markInfeasible(bool branch) {
319     if (branch)
320       InFeasibleTrue = GeneratedTrue = true;
321     else
322       InFeasibleFalse = GeneratedFalse = true;
323   }
324 
isFeasible(bool branch)325   bool isFeasible(bool branch) {
326     return branch ? !InFeasibleTrue : !InFeasibleFalse;
327   }
328 
getState()329   const GRState* getState() const {
330     return getPredecessor()->getState();
331   }
332 };
333 
334 class IndirectGotoNodeBuilder {
335   CoreEngine& Eng;
336   const CFGBlock* Src;
337   const CFGBlock& DispatchBlock;
338   const Expr* E;
339   ExplodedNode* Pred;
340 
341 public:
IndirectGotoNodeBuilder(ExplodedNode * pred,const CFGBlock * src,const Expr * e,const CFGBlock * dispatch,CoreEngine * eng)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) {}
345 
346   class iterator {
347     CFGBlock::const_succ_iterator I;
348 
349     friend class IndirectGotoNodeBuilder;
iterator(CFGBlock::const_succ_iterator i)350     iterator(CFGBlock::const_succ_iterator i) : I(i) {}
351   public:
352 
353     iterator& operator++() { ++I; return *this; }
354     bool operator!=(const iterator& X) const { return I != X.I; }
355 
getLabel()356     const LabelDecl *getLabel() const {
357       return llvm::cast<LabelStmt>((*I)->getLabel())->getDecl();
358     }
359 
getBlock()360     const CFGBlock *getBlock() const {
361       return *I;
362     }
363   };
364 
begin()365   iterator begin() { return iterator(DispatchBlock.succ_begin()); }
end()366   iterator end() { return iterator(DispatchBlock.succ_end()); }
367 
368   ExplodedNode* generateNode(const iterator& I, const GRState* State,
369                              bool isSink = false);
370 
getTarget()371   const Expr* getTarget() const { return E; }
372 
getState()373   const GRState* getState() const { return Pred->State; }
374 };
375 
376 class SwitchNodeBuilder {
377   CoreEngine& Eng;
378   const CFGBlock* Src;
379   const Expr* Condition;
380   ExplodedNode* Pred;
381 
382 public:
SwitchNodeBuilder(ExplodedNode * pred,const CFGBlock * src,const Expr * condition,CoreEngine * eng)383   SwitchNodeBuilder(ExplodedNode* pred, const CFGBlock* src,
384                       const Expr* condition, CoreEngine* eng)
385   : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
386 
387   class iterator {
388     CFGBlock::const_succ_reverse_iterator I;
389 
390     friend class SwitchNodeBuilder;
iterator(CFGBlock::const_succ_reverse_iterator i)391     iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {}
392 
393   public:
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; }
397 
getCase()398     const CaseStmt* getCase() const {
399       return llvm::cast<CaseStmt>((*I)->getLabel());
400     }
401 
getBlock()402     const CFGBlock* getBlock() const {
403       return *I;
404     }
405   };
406 
begin()407   iterator begin() { return iterator(Src->succ_rbegin()+1); }
end()408   iterator end() { return iterator(Src->succ_rend()); }
409 
getSwitch()410   const SwitchStmt *getSwitch() const {
411     return llvm::cast<SwitchStmt>(Src->getTerminator());
412   }
413 
414   ExplodedNode* generateCaseStmtNode(const iterator& I, const GRState* State);
415 
416   ExplodedNode* generateDefaultCaseNode(const GRState* State,
417                                         bool isSink = false);
418 
getCondition()419   const Expr* getCondition() const { return Condition; }
420 
getState()421   const GRState* getState() const { return Pred->State; }
422 };
423 
424 class GenericNodeBuilderImpl {
425 protected:
426   CoreEngine &engine;
427   ExplodedNode *pred;
428   ProgramPoint pp;
429   llvm::SmallVector<ExplodedNode*, 2> sinksGenerated;
430 
431   ExplodedNode *generateNodeImpl(const GRState *state, ExplodedNode *pred,
432                                  ProgramPoint programPoint, bool asSink);
433 
GenericNodeBuilderImpl(CoreEngine & eng,ExplodedNode * pr,ProgramPoint p)434   GenericNodeBuilderImpl(CoreEngine &eng, ExplodedNode *pr, ProgramPoint p)
435     : engine(eng), pred(pr), pp(p), hasGeneratedNode(false) {}
436 
437 public:
438   bool hasGeneratedNode;
439 
getWorkList()440   WorkList &getWorkList() { return *engine.WList; }
441 
getPredecessor()442   ExplodedNode* getPredecessor() const { return pred; }
443 
getBlockCounter()444   BlockCounter getBlockCounter() const {
445     return engine.WList->getBlockCounter();
446   }
447 
sinks()448   const llvm::SmallVectorImpl<ExplodedNode*> &sinks() const {
449     return sinksGenerated;
450   }
451 };
452 
453 template <typename PP_T>
454 class GenericNodeBuilder : public GenericNodeBuilderImpl {
455 public:
GenericNodeBuilder(CoreEngine & eng,ExplodedNode * pr,const PP_T & p)456   GenericNodeBuilder(CoreEngine &eng, ExplodedNode *pr, const PP_T &p)
457     : GenericNodeBuilderImpl(eng, pr, p) {}
458 
generateNode(const GRState * state,ExplodedNode * pred,const void * tag,bool asSink)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),
462                             asSink);
463   }
464 
getProgramPoint()465   const PP_T &getProgramPoint() const { return cast<PP_T>(pp); }
466 };
467 
468 class EndOfFunctionNodeBuilder {
469   CoreEngine &Eng;
470   const CFGBlock& B;
471   ExplodedNode* Pred;
472   void *Tag;
473 
474 public:
475   bool hasGeneratedNode;
476 
477 public:
478   EndOfFunctionNodeBuilder(const CFGBlock* b, ExplodedNode* N, CoreEngine* e,
479                            void *checkerTag = 0)
480     : Eng(*e), B(*b), Pred(N), Tag(checkerTag), hasGeneratedNode(false) {}
481 
482   ~EndOfFunctionNodeBuilder();
483 
withCheckerTag(void * tag)484   EndOfFunctionNodeBuilder withCheckerTag(void *tag) {
485     return EndOfFunctionNodeBuilder(&B, Pred, &Eng, tag);
486   }
487 
getWorkList()488   WorkList &getWorkList() { return *Eng.WList; }
489 
getPredecessor()490   ExplodedNode* getPredecessor() const { return Pred; }
491 
getBlockCounter()492   BlockCounter getBlockCounter() const {
493     return Eng.WList->getBlockCounter();
494   }
495 
getCurrentBlockCount()496   unsigned getCurrentBlockCount() const {
497     return getBlockCounter().getNumVisited(
498                             Pred->getLocationContext()->getCurrentStackFrame(),
499                                            B.getBlockID());
500   }
501 
502   ExplodedNode* generateNode(const GRState* State, ExplodedNode *P = 0,
503                              const void *tag = 0);
504 
505   void GenerateCallExitNode(const GRState *state);
506 
getBlock()507   const CFGBlock* getBlock() const { return &B; }
508 
getState()509   const GRState* getState() const {
510     return getPredecessor()->getState();
511   }
512 };
513 
514 class CallEnterNodeBuilder {
515   CoreEngine &Eng;
516 
517   const ExplodedNode *Pred;
518 
519   // The call site. For implicit automatic object dtor, this is the trigger
520   // statement.
521   const Stmt *CE;
522 
523   // The context of the callee.
524   const StackFrameContext *CalleeCtx;
525 
526   // The parent block of the CallExpr.
527   const CFGBlock *Block;
528 
529   // The CFGBlock index of the CallExpr.
530   unsigned Index;
531 
532 public:
CallEnterNodeBuilder(CoreEngine & eng,const ExplodedNode * pred,const Stmt * s,const StackFrameContext * callee,const CFGBlock * blk,unsigned idx)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) {}
537 
getState()538   const GRState *getState() const { return Pred->getState(); }
539 
getLocationContext()540   const LocationContext *getLocationContext() const {
541     return Pred->getLocationContext();
542   }
543 
getCallExpr()544   const Stmt *getCallExpr() const { return CE; }
545 
getCalleeContext()546   const StackFrameContext *getCalleeContext() const { return CalleeCtx; }
547 
getBlock()548   const CFGBlock *getBlock() const { return Block; }
549 
getIndex()550   unsigned getIndex() const { return Index; }
551 
552   void generateNode(const GRState *state);
553 };
554 
555 class CallExitNodeBuilder {
556   CoreEngine &Eng;
557   const ExplodedNode *Pred;
558 
559 public:
CallExitNodeBuilder(CoreEngine & eng,const ExplodedNode * pred)560   CallExitNodeBuilder(CoreEngine &eng, const ExplodedNode *pred)
561     : Eng(eng), Pred(pred) {}
562 
getPredecessor()563   const ExplodedNode *getPredecessor() const { return Pred; }
564 
getState()565   const GRState *getState() const { return Pred->getState(); }
566 
567   void generateNode(const GRState *state);
568 };
569 
570 } // end GR namespace
571 
572 } // end clang namespace
573 
574 #endif
575