• 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_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
16 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_COREENGINE_H
17 
18 #include "clang/AST/Expr.h"
19 #include "clang/Analysis/AnalysisContext.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
21 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
22 #include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h"
23 #include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
24 #include <memory>
25 
26 namespace clang {
27 
28 class ProgramPointTag;
29 
30 namespace ento {
31 
32 class NodeBuilder;
33 
34 //===----------------------------------------------------------------------===//
35 /// CoreEngine - Implements the core logic of the graph-reachability
36 ///   analysis. It traverses the CFG and generates the ExplodedGraph.
37 ///   Program "states" are treated as opaque void pointers.
38 ///   The template class CoreEngine (which subclasses CoreEngine)
39 ///   provides the matching component to the engine that knows the actual types
40 ///   for states.  Note that this engine only dispatches to transfer functions
41 ///   at the statement and block-level.  The analyses themselves must implement
42 ///   any transfer function logic and the sub-expression level (if any).
43 class CoreEngine {
44   friend struct NodeBuilderContext;
45   friend class NodeBuilder;
46   friend class ExprEngine;
47   friend class CommonNodeBuilder;
48   friend class IndirectGotoNodeBuilder;
49   friend class SwitchNodeBuilder;
50   friend class EndOfFunctionNodeBuilder;
51 public:
52   typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> >
53             BlocksExhausted;
54 
55   typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> >
56             BlocksAborted;
57 
58 private:
59 
60   SubEngine& SubEng;
61 
62   /// G - The simulation graph.  Each node is a (location,state) pair.
63   mutable ExplodedGraph G;
64 
65   /// WList - A set of queued nodes that need to be processed by the
66   ///  worklist algorithm.  It is up to the implementation of WList to decide
67   ///  the order that nodes are processed.
68   std::unique_ptr<WorkList> WList;
69 
70   /// BCounterFactory - A factory object for created BlockCounter objects.
71   ///   These are used to record for key nodes in the ExplodedGraph the
72   ///   number of times different CFGBlocks have been visited along a path.
73   BlockCounter::Factory BCounterFactory;
74 
75   /// The locations where we stopped doing work because we visited a location
76   ///  too many times.
77   BlocksExhausted blocksExhausted;
78 
79   /// The locations where we stopped because the engine aborted analysis,
80   /// usually because it could not reason about something.
81   BlocksAborted blocksAborted;
82 
83   /// The information about functions shared by the whole translation unit.
84   /// (This data is owned by AnalysisConsumer.)
85   FunctionSummariesTy *FunctionSummaries;
86 
87   void generateNode(const ProgramPoint &Loc,
88                     ProgramStateRef State,
89                     ExplodedNode *Pred);
90 
91   void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred);
92   void HandleBlockEntrance(const BlockEntrance &E, ExplodedNode *Pred);
93   void HandleBlockExit(const CFGBlock *B, ExplodedNode *Pred);
94   void HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred);
95 
96   void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B,
97                     ExplodedNode *Pred);
98   void HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
99                                     const CFGBlock *B, ExplodedNode *Pred);
100 
101   /// Handle conditional logic for running static initializers.
102   void HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
103                         ExplodedNode *Pred);
104 
105 private:
106   CoreEngine(const CoreEngine &) = delete;
107   void operator=(const CoreEngine &) = delete;
108 
109   ExplodedNode *generateCallExitBeginNode(ExplodedNode *N);
110 
111 public:
112   /// Construct a CoreEngine object to analyze the provided CFG.
CoreEngine(SubEngine & subengine,FunctionSummariesTy * FS)113   CoreEngine(SubEngine &subengine, FunctionSummariesTy *FS)
114       : SubEng(subengine), WList(WorkList::makeDFS()),
115         BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {}
116 
117   /// getGraph - Returns the exploded graph.
getGraph()118   ExplodedGraph &getGraph() { return G; }
119 
120   /// ExecuteWorkList - Run the worklist algorithm for a maximum number of
121   ///  steps.  Returns true if there is still simulation state on the worklist.
122   bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
123                        ProgramStateRef InitState);
124   /// Returns true if there is still simulation state on the worklist.
125   bool ExecuteWorkListWithInitialState(const LocationContext *L,
126                                        unsigned Steps,
127                                        ProgramStateRef InitState,
128                                        ExplodedNodeSet &Dst);
129 
130   /// Dispatch the work list item based on the given location information.
131   /// Use Pred parameter as the predecessor state.
132   void dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
133                         const WorkListUnit& WU);
134 
135   // Functions for external checking of whether we have unfinished work
wasBlockAborted()136   bool wasBlockAborted() const { return !blocksAborted.empty(); }
wasBlocksExhausted()137   bool wasBlocksExhausted() const { return !blocksExhausted.empty(); }
hasWorkRemaining()138   bool hasWorkRemaining() const { return wasBlocksExhausted() ||
139                                          WList->hasWork() ||
140                                          wasBlockAborted(); }
141 
142   /// Inform the CoreEngine that a basic block was aborted because
143   /// it could not be completely analyzed.
addAbortedBlock(const ExplodedNode * node,const CFGBlock * block)144   void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) {
145     blocksAborted.push_back(std::make_pair(block, node));
146   }
147 
getWorkList()148   WorkList *getWorkList() const { return WList.get(); }
149 
blocks_exhausted_begin()150   BlocksExhausted::const_iterator blocks_exhausted_begin() const {
151     return blocksExhausted.begin();
152   }
blocks_exhausted_end()153   BlocksExhausted::const_iterator blocks_exhausted_end() const {
154     return blocksExhausted.end();
155   }
blocks_aborted_begin()156   BlocksAborted::const_iterator blocks_aborted_begin() const {
157     return blocksAborted.begin();
158   }
blocks_aborted_end()159   BlocksAborted::const_iterator blocks_aborted_end() const {
160     return blocksAborted.end();
161   }
162 
163   /// \brief Enqueue the given set of nodes onto the work list.
164   void enqueue(ExplodedNodeSet &Set);
165 
166   /// \brief Enqueue nodes that were created as a result of processing
167   /// a statement onto the work list.
168   void enqueue(ExplodedNodeSet &Set, const CFGBlock *Block, unsigned Idx);
169 
170   /// \brief enqueue the nodes corresponding to the end of function onto the
171   /// end of path / work list.
172   void enqueueEndOfFunction(ExplodedNodeSet &Set);
173 
174   /// \brief Enqueue a single node created as a result of statement processing.
175   void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx);
176 };
177 
178 // TODO: Turn into a calss.
179 struct NodeBuilderContext {
180   const CoreEngine &Eng;
181   const CFGBlock *Block;
182   const LocationContext *LC;
NodeBuilderContextNodeBuilderContext183   NodeBuilderContext(const CoreEngine &E, const CFGBlock *B, ExplodedNode *N)
184     : Eng(E), Block(B), LC(N->getLocationContext()) { assert(B); }
185 
186   /// \brief Return the CFGBlock associated with this builder.
getBlockNodeBuilderContext187   const CFGBlock *getBlock() const { return Block; }
188 
189   /// \brief Returns the number of times the current basic block has been
190   /// visited on the exploded graph path.
blockCountNodeBuilderContext191   unsigned blockCount() const {
192     return Eng.WList->getBlockCounter().getNumVisited(
193                     LC->getCurrentStackFrame(),
194                     Block->getBlockID());
195   }
196 };
197 
198 /// \class NodeBuilder
199 /// \brief This is the simplest builder which generates nodes in the
200 /// ExplodedGraph.
201 ///
202 /// The main benefit of the builder is that it automatically tracks the
203 /// frontier nodes (or destination set). This is the set of nodes which should
204 /// be propagated to the next step / builder. They are the nodes which have been
205 /// added to the builder (either as the input node set or as the newly
206 /// constructed nodes) but did not have any outgoing transitions added.
207 class NodeBuilder {
208   virtual void anchor();
209 protected:
210   const NodeBuilderContext &C;
211 
212   /// Specifies if the builder results have been finalized. For example, if it
213   /// is set to false, autotransitions are yet to be generated.
214   bool Finalized;
215   bool HasGeneratedNodes;
216   /// \brief The frontier set - a set of nodes which need to be propagated after
217   /// the builder dies.
218   ExplodedNodeSet &Frontier;
219 
220   /// Checkes if the results are ready.
checkResults()221   virtual bool checkResults() {
222     if (!Finalized)
223       return false;
224     return true;
225   }
226 
hasNoSinksInFrontier()227   bool hasNoSinksInFrontier() {
228     for (iterator I = Frontier.begin(), E = Frontier.end(); I != E; ++I) {
229       if ((*I)->isSink())
230         return false;
231     }
232     return true;
233   }
234 
235   /// Allow subclasses to finalize results before result_begin() is executed.
finalizeResults()236   virtual void finalizeResults() {}
237 
238   ExplodedNode *generateNodeImpl(const ProgramPoint &PP,
239                                  ProgramStateRef State,
240                                  ExplodedNode *Pred,
241                                  bool MarkAsSink = false);
242 
243 public:
244   NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
245               const NodeBuilderContext &Ctx, bool F = true)
C(Ctx)246     : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) {
247     Frontier.Add(SrcNode);
248   }
249 
250   NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
251               const NodeBuilderContext &Ctx, bool F = true)
C(Ctx)252     : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) {
253     Frontier.insert(SrcSet);
254     assert(hasNoSinksInFrontier());
255   }
256 
~NodeBuilder()257   virtual ~NodeBuilder() {}
258 
259   /// \brief Generates a node in the ExplodedGraph.
generateNode(const ProgramPoint & PP,ProgramStateRef State,ExplodedNode * Pred)260   ExplodedNode *generateNode(const ProgramPoint &PP,
261                              ProgramStateRef State,
262                              ExplodedNode *Pred) {
263     return generateNodeImpl(PP, State, Pred, false);
264   }
265 
266   /// \brief Generates a sink in the ExplodedGraph.
267   ///
268   /// When a node is marked as sink, the exploration from the node is stopped -
269   /// the node becomes the last node on the path and certain kinds of bugs are
270   /// suppressed.
generateSink(const ProgramPoint & PP,ProgramStateRef State,ExplodedNode * Pred)271   ExplodedNode *generateSink(const ProgramPoint &PP,
272                              ProgramStateRef State,
273                              ExplodedNode *Pred) {
274     return generateNodeImpl(PP, State, Pred, true);
275   }
276 
getResults()277   const ExplodedNodeSet &getResults() {
278     finalizeResults();
279     assert(checkResults());
280     return Frontier;
281   }
282 
283   typedef ExplodedNodeSet::iterator iterator;
284   /// \brief Iterators through the results frontier.
begin()285   inline iterator begin() {
286     finalizeResults();
287     assert(checkResults());
288     return Frontier.begin();
289   }
end()290   inline iterator end() {
291     finalizeResults();
292     return Frontier.end();
293   }
294 
getContext()295   const NodeBuilderContext &getContext() { return C; }
hasGeneratedNodes()296   bool hasGeneratedNodes() { return HasGeneratedNodes; }
297 
takeNodes(const ExplodedNodeSet & S)298   void takeNodes(const ExplodedNodeSet &S) {
299     for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I )
300       Frontier.erase(*I);
301   }
takeNodes(ExplodedNode * N)302   void takeNodes(ExplodedNode *N) { Frontier.erase(N); }
addNodes(const ExplodedNodeSet & S)303   void addNodes(const ExplodedNodeSet &S) { Frontier.insert(S); }
addNodes(ExplodedNode * N)304   void addNodes(ExplodedNode *N) { Frontier.Add(N); }
305 };
306 
307 /// \class NodeBuilderWithSinks
308 /// \brief This node builder keeps track of the generated sink nodes.
309 class NodeBuilderWithSinks: public NodeBuilder {
310   void anchor() override;
311 protected:
312   SmallVector<ExplodedNode*, 2> sinksGenerated;
313   ProgramPoint &Location;
314 
315 public:
NodeBuilderWithSinks(ExplodedNode * Pred,ExplodedNodeSet & DstSet,const NodeBuilderContext & Ctx,ProgramPoint & L)316   NodeBuilderWithSinks(ExplodedNode *Pred, ExplodedNodeSet &DstSet,
317                        const NodeBuilderContext &Ctx, ProgramPoint &L)
318     : NodeBuilder(Pred, DstSet, Ctx), Location(L) {}
319 
320   ExplodedNode *generateNode(ProgramStateRef State,
321                              ExplodedNode *Pred,
322                              const ProgramPointTag *Tag = nullptr) {
323     const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
324     return NodeBuilder::generateNode(LocalLoc, State, Pred);
325   }
326 
327   ExplodedNode *generateSink(ProgramStateRef State, ExplodedNode *Pred,
328                              const ProgramPointTag *Tag = nullptr) {
329     const ProgramPoint &LocalLoc = (Tag ? Location.withTag(Tag) : Location);
330     ExplodedNode *N = NodeBuilder::generateSink(LocalLoc, State, Pred);
331     if (N && N->isSink())
332       sinksGenerated.push_back(N);
333     return N;
334   }
335 
getSinks()336   const SmallVectorImpl<ExplodedNode*> &getSinks() const {
337     return sinksGenerated;
338   }
339 };
340 
341 /// \class StmtNodeBuilder
342 /// \brief This builder class is useful for generating nodes that resulted from
343 /// visiting a statement. The main difference from its parent NodeBuilder is
344 /// that it creates a statement specific ProgramPoint.
345 class StmtNodeBuilder: public NodeBuilder {
346   NodeBuilder *EnclosingBldr;
347 public:
348 
349   /// \brief Constructs a StmtNodeBuilder. If the builder is going to process
350   /// nodes currently owned by another builder(with larger scope), use
351   /// Enclosing builder to transfer ownership.
352   StmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
353                   const NodeBuilderContext &Ctx,
354                   NodeBuilder *Enclosing = nullptr)
NodeBuilder(SrcNode,DstSet,Ctx)355     : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) {
356     if (EnclosingBldr)
357       EnclosingBldr->takeNodes(SrcNode);
358   }
359 
360   StmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
361                   const NodeBuilderContext &Ctx,
362                   NodeBuilder *Enclosing = nullptr)
NodeBuilder(SrcSet,DstSet,Ctx)363     : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) {
364     if (EnclosingBldr)
365       for (ExplodedNodeSet::iterator I = SrcSet.begin(),
366                                      E = SrcSet.end(); I != E; ++I )
367         EnclosingBldr->takeNodes(*I);
368   }
369 
370   ~StmtNodeBuilder() override;
371 
372   using NodeBuilder::generateNode;
373   using NodeBuilder::generateSink;
374 
375   ExplodedNode *generateNode(const Stmt *S,
376                              ExplodedNode *Pred,
377                              ProgramStateRef St,
378                              const ProgramPointTag *tag = nullptr,
379                              ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
380     const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
381                                   Pred->getLocationContext(), tag);
382     return NodeBuilder::generateNode(L, St, Pred);
383   }
384 
385   ExplodedNode *generateSink(const Stmt *S,
386                              ExplodedNode *Pred,
387                              ProgramStateRef St,
388                              const ProgramPointTag *tag = nullptr,
389                              ProgramPoint::Kind K = ProgramPoint::PostStmtKind){
390     const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
391                                   Pred->getLocationContext(), tag);
392     return NodeBuilder::generateSink(L, St, Pred);
393   }
394 };
395 
396 /// \brief BranchNodeBuilder is responsible for constructing the nodes
397 /// corresponding to the two branches of the if statement - true and false.
398 class BranchNodeBuilder: public NodeBuilder {
399   void anchor() override;
400   const CFGBlock *DstT;
401   const CFGBlock *DstF;
402 
403   bool InFeasibleTrue;
404   bool InFeasibleFalse;
405 
406 public:
BranchNodeBuilder(ExplodedNode * SrcNode,ExplodedNodeSet & DstSet,const NodeBuilderContext & C,const CFGBlock * dstT,const CFGBlock * dstF)407   BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
408                     const NodeBuilderContext &C,
409                     const CFGBlock *dstT, const CFGBlock *dstF)
410   : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF),
411     InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
412     // The branch node builder does not generate autotransitions.
413     // If there are no successors it means that both branches are infeasible.
414     takeNodes(SrcNode);
415   }
416 
BranchNodeBuilder(const ExplodedNodeSet & SrcSet,ExplodedNodeSet & DstSet,const NodeBuilderContext & C,const CFGBlock * dstT,const CFGBlock * dstF)417   BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
418                     const NodeBuilderContext &C,
419                     const CFGBlock *dstT, const CFGBlock *dstF)
420   : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF),
421     InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
422     takeNodes(SrcSet);
423   }
424 
425   ExplodedNode *generateNode(ProgramStateRef State, bool branch,
426                              ExplodedNode *Pred);
427 
getTargetBlock(bool branch)428   const CFGBlock *getTargetBlock(bool branch) const {
429     return branch ? DstT : DstF;
430   }
431 
markInfeasible(bool branch)432   void markInfeasible(bool branch) {
433     if (branch)
434       InFeasibleTrue = true;
435     else
436       InFeasibleFalse = true;
437   }
438 
isFeasible(bool branch)439   bool isFeasible(bool branch) {
440     return branch ? !InFeasibleTrue : !InFeasibleFalse;
441   }
442 };
443 
444 class IndirectGotoNodeBuilder {
445   CoreEngine& Eng;
446   const CFGBlock *Src;
447   const CFGBlock &DispatchBlock;
448   const Expr *E;
449   ExplodedNode *Pred;
450 
451 public:
IndirectGotoNodeBuilder(ExplodedNode * pred,const CFGBlock * src,const Expr * e,const CFGBlock * dispatch,CoreEngine * eng)452   IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
453                     const Expr *e, const CFGBlock *dispatch, CoreEngine* eng)
454     : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
455 
456   class iterator {
457     CFGBlock::const_succ_iterator I;
458 
459     friend class IndirectGotoNodeBuilder;
iterator(CFGBlock::const_succ_iterator i)460     iterator(CFGBlock::const_succ_iterator i) : I(i) {}
461   public:
462 
463     iterator &operator++() { ++I; return *this; }
464     bool operator!=(const iterator &X) const { return I != X.I; }
465 
getLabel()466     const LabelDecl *getLabel() const {
467       return cast<LabelStmt>((*I)->getLabel())->getDecl();
468     }
469 
getBlock()470     const CFGBlock *getBlock() const {
471       return *I;
472     }
473   };
474 
begin()475   iterator begin() { return iterator(DispatchBlock.succ_begin()); }
end()476   iterator end() { return iterator(DispatchBlock.succ_end()); }
477 
478   ExplodedNode *generateNode(const iterator &I,
479                              ProgramStateRef State,
480                              bool isSink = false);
481 
getTarget()482   const Expr *getTarget() const { return E; }
483 
getState()484   ProgramStateRef getState() const { return Pred->State; }
485 
getLocationContext()486   const LocationContext *getLocationContext() const {
487     return Pred->getLocationContext();
488   }
489 };
490 
491 class SwitchNodeBuilder {
492   CoreEngine& Eng;
493   const CFGBlock *Src;
494   const Expr *Condition;
495   ExplodedNode *Pred;
496 
497 public:
SwitchNodeBuilder(ExplodedNode * pred,const CFGBlock * src,const Expr * condition,CoreEngine * eng)498   SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src,
499                     const Expr *condition, CoreEngine* eng)
500   : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
501 
502   class iterator {
503     CFGBlock::const_succ_reverse_iterator I;
504 
505     friend class SwitchNodeBuilder;
iterator(CFGBlock::const_succ_reverse_iterator i)506     iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {}
507 
508   public:
509     iterator &operator++() { ++I; return *this; }
510     bool operator!=(const iterator &X) const { return I != X.I; }
511     bool operator==(const iterator &X) const { return I == X.I; }
512 
getCase()513     const CaseStmt *getCase() const {
514       return cast<CaseStmt>((*I)->getLabel());
515     }
516 
getBlock()517     const CFGBlock *getBlock() const {
518       return *I;
519     }
520   };
521 
begin()522   iterator begin() { return iterator(Src->succ_rbegin()+1); }
end()523   iterator end() { return iterator(Src->succ_rend()); }
524 
getSwitch()525   const SwitchStmt *getSwitch() const {
526     return cast<SwitchStmt>(Src->getTerminator());
527   }
528 
529   ExplodedNode *generateCaseStmtNode(const iterator &I,
530                                      ProgramStateRef State);
531 
532   ExplodedNode *generateDefaultCaseNode(ProgramStateRef State,
533                                         bool isSink = false);
534 
getCondition()535   const Expr *getCondition() const { return Condition; }
536 
getState()537   ProgramStateRef getState() const { return Pred->State; }
538 
getLocationContext()539   const LocationContext *getLocationContext() const {
540     return Pred->getLocationContext();
541   }
542 };
543 
544 } // end ento namespace
545 } // end clang namespace
546 
547 #endif
548