clang  3.7.0
CoreEngine.cpp
Go to the documentation of this file.
1 //==- CoreEngine.cpp - 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 engine.
12 //
13 //===----------------------------------------------------------------------===//
14 
16 #include "clang/AST/Expr.h"
17 #include "clang/AST/ExprCXX.h"
18 #include "clang/AST/StmtCXX.h"
21 #include "llvm/ADT/DenseMap.h"
22 #include "llvm/ADT/Statistic.h"
23 #include "llvm/Support/Casting.h"
24 
25 using namespace clang;
26 using namespace ento;
27 
28 #define DEBUG_TYPE "CoreEngine"
29 
30 STATISTIC(NumSteps,
31  "The # of steps executed.");
32 STATISTIC(NumReachedMaxSteps,
33  "The # of times we reached the max number of steps.");
34 STATISTIC(NumPathsExplored,
35  "The # of paths explored by the analyzer.");
36 
37 //===----------------------------------------------------------------------===//
38 // Worklist classes for exploration of reachable states.
39 //===----------------------------------------------------------------------===//
40 
42 
43 namespace {
44 class DFS : public WorkList {
46 public:
47  bool hasWork() const override {
48  return !Stack.empty();
49  }
50 
51  void enqueue(const WorkListUnit& U) override {
52  Stack.push_back(U);
53  }
54 
55  WorkListUnit dequeue() override {
56  assert (!Stack.empty());
57  const WorkListUnit& U = Stack.back();
58  Stack.pop_back(); // This technically "invalidates" U, but we are fine.
59  return U;
60  }
61 
62  bool visitItemsInWorkList(Visitor &V) override {
64  I = Stack.begin(), E = Stack.end(); I != E; ++I) {
65  if (V.visit(*I))
66  return true;
67  }
68  return false;
69  }
70 };
71 
72 class BFS : public WorkList {
73  std::deque<WorkListUnit> Queue;
74 public:
75  bool hasWork() const override {
76  return !Queue.empty();
77  }
78 
79  void enqueue(const WorkListUnit& U) override {
80  Queue.push_back(U);
81  }
82 
83  WorkListUnit dequeue() override {
84  WorkListUnit U = Queue.front();
85  Queue.pop_front();
86  return U;
87  }
88 
89  bool visitItemsInWorkList(Visitor &V) override {
90  for (std::deque<WorkListUnit>::iterator
91  I = Queue.begin(), E = Queue.end(); I != E; ++I) {
92  if (V.visit(*I))
93  return true;
94  }
95  return false;
96  }
97 };
98 
99 } // end anonymous namespace
100 
101 // Place the dstor for WorkList here because it contains virtual member
102 // functions, and we the code for the dstor generated in one compilation unit.
104 
105 WorkList *WorkList::makeDFS() { return new DFS(); }
106 WorkList *WorkList::makeBFS() { return new BFS(); }
107 
108 namespace {
109  class BFSBlockDFSContents : public WorkList {
110  std::deque<WorkListUnit> Queue;
112  public:
113  bool hasWork() const override {
114  return !Queue.empty() || !Stack.empty();
115  }
116 
117  void enqueue(const WorkListUnit& U) override {
118  if (U.getNode()->getLocation().getAs<BlockEntrance>())
119  Queue.push_front(U);
120  else
121  Stack.push_back(U);
122  }
123 
124  WorkListUnit dequeue() override {
125  // Process all basic blocks to completion.
126  if (!Stack.empty()) {
127  const WorkListUnit& U = Stack.back();
128  Stack.pop_back(); // This technically "invalidates" U, but we are fine.
129  return U;
130  }
131 
132  assert(!Queue.empty());
133  // Don't use const reference. The subsequent pop_back() might make it
134  // unsafe.
135  WorkListUnit U = Queue.front();
136  Queue.pop_front();
137  return U;
138  }
139  bool visitItemsInWorkList(Visitor &V) override {
141  I = Stack.begin(), E = Stack.end(); I != E; ++I) {
142  if (V.visit(*I))
143  return true;
144  }
145  for (std::deque<WorkListUnit>::iterator
146  I = Queue.begin(), E = Queue.end(); I != E; ++I) {
147  if (V.visit(*I))
148  return true;
149  }
150  return false;
151  }
152 
153  };
154 } // end anonymous namespace
155 
157  return new BFSBlockDFSContents();
158 }
159 
160 //===----------------------------------------------------------------------===//
161 // Core analysis engine.
162 //===----------------------------------------------------------------------===//
163 
164 /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
165 bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps,
166  ProgramStateRef InitState) {
167 
168  if (G.num_roots() == 0) { // Initialize the analysis by constructing
169  // the root if none exists.
170 
171  const CFGBlock *Entry = &(L->getCFG()->getEntry());
172 
173  assert (Entry->empty() &&
174  "Entry block must be empty.");
175 
176  assert (Entry->succ_size() == 1 &&
177  "Entry block must have 1 successor.");
178 
179  // Mark the entry block as visited.
180  FunctionSummaries->markVisitedBasicBlock(Entry->getBlockID(),
181  L->getDecl(),
182  L->getCFG()->getNumBlockIDs());
183 
184  // Get the solitary successor.
185  const CFGBlock *Succ = *(Entry->succ_begin());
186 
187  // Construct an edge representing the
188  // starting location in the function.
189  BlockEdge StartLoc(Entry, Succ, L);
190 
191  // Set the current block counter to being empty.
192  WList->setBlockCounter(BCounterFactory.GetEmptyCounter());
193 
194  if (!InitState)
195  // Generate the root.
196  generateNode(StartLoc, SubEng.getInitialState(L), nullptr);
197  else
198  generateNode(StartLoc, InitState, nullptr);
199  }
200 
201  // Check if we have a steps limit
202  bool UnlimitedSteps = Steps == 0;
203 
204  while (WList->hasWork()) {
205  if (!UnlimitedSteps) {
206  if (Steps == 0) {
207  NumReachedMaxSteps++;
208  break;
209  }
210  --Steps;
211  }
212 
213  NumSteps++;
214 
215  const WorkListUnit& WU = WList->dequeue();
216 
217  // Set the current block counter.
218  WList->setBlockCounter(WU.getBlockCounter());
219 
220  // Retrieve the node.
221  ExplodedNode *Node = WU.getNode();
222 
223  dispatchWorkItem(Node, Node->getLocation(), WU);
224  }
225  SubEng.processEndWorklist(hasWorkRemaining());
226  return WList->hasWork();
227 }
228 
230  const WorkListUnit& WU) {
231  // Dispatch on the location type.
232  switch (Loc.getKind()) {
234  HandleBlockEdge(Loc.castAs<BlockEdge>(), Pred);
235  break;
236 
238  HandleBlockEntrance(Loc.castAs<BlockEntrance>(), Pred);
239  break;
240 
242  assert (false && "BlockExit location never occur in forward analysis.");
243  break;
244 
246  CallEnter CEnter = Loc.castAs<CallEnter>();
247  SubEng.processCallEnter(CEnter, Pred);
248  break;
249  }
250 
252  SubEng.processCallExit(Pred);
253  break;
254 
256  assert(Pred->hasSinglePred() &&
257  "Assume epsilon has exactly one predecessor by construction");
258  ExplodedNode *PNode = Pred->getFirstPred();
259  dispatchWorkItem(Pred, PNode->getLocation(), WU);
260  break;
261  }
262  default:
263  assert(Loc.getAs<PostStmt>() ||
264  Loc.getAs<PostInitializer>() ||
265  Loc.getAs<PostImplicitCall>() ||
266  Loc.getAs<CallExitEnd>());
267  HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
268  break;
269  }
270 }
271 
273  unsigned Steps,
274  ProgramStateRef InitState,
275  ExplodedNodeSet &Dst) {
276  bool DidNotFinish = ExecuteWorkList(L, Steps, InitState);
277  for (ExplodedGraph::eop_iterator I = G.eop_begin(), E = G.eop_end(); I != E;
278  ++I) {
279  Dst.Add(*I);
280  }
281  return DidNotFinish;
282 }
283 
284 void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
285 
286  const CFGBlock *Blk = L.getDst();
287  NodeBuilderContext BuilderCtx(*this, Blk, Pred);
288 
289  // Mark this block as visited.
290  const LocationContext *LC = Pred->getLocationContext();
291  FunctionSummaries->markVisitedBasicBlock(Blk->getBlockID(),
292  LC->getDecl(),
293  LC->getCFG()->getNumBlockIDs());
294 
295  // Check if we are entering the EXIT block.
296  if (Blk == &(L.getLocationContext()->getCFG()->getExit())) {
297 
298  assert (L.getLocationContext()->getCFG()->getExit().size() == 0
299  && "EXIT block cannot contain Stmts.");
300 
301  // Process the final state transition.
302  SubEng.processEndOfFunction(BuilderCtx, Pred);
303 
304  // This path is done. Don't enqueue any more nodes.
305  return;
306  }
307 
308  // Call into the SubEngine to process entering the CFGBlock.
309  ExplodedNodeSet dstNodes;
310  BlockEntrance BE(Blk, Pred->getLocationContext());
311  NodeBuilderWithSinks nodeBuilder(Pred, dstNodes, BuilderCtx, BE);
312  SubEng.processCFGBlockEntrance(L, nodeBuilder, Pred);
313 
314  // Auto-generate a node.
315  if (!nodeBuilder.hasGeneratedNodes()) {
316  nodeBuilder.generateNode(Pred->State, Pred);
317  }
318 
319  // Enqueue nodes onto the worklist.
320  enqueue(dstNodes);
321 }
322 
323 void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
324  ExplodedNode *Pred) {
325 
326  // Increment the block counter.
327  const LocationContext *LC = Pred->getLocationContext();
328  unsigned BlockId = L.getBlock()->getBlockID();
329  BlockCounter Counter = WList->getBlockCounter();
330  Counter = BCounterFactory.IncrementCount(Counter, LC->getCurrentStackFrame(),
331  BlockId);
332  WList->setBlockCounter(Counter);
333 
334  // Process the entrance of the block.
336  NodeBuilderContext Ctx(*this, L.getBlock(), Pred);
337  SubEng.processCFGElement(*E, Pred, 0, &Ctx);
338  }
339  else
340  HandleBlockExit(L.getBlock(), Pred);
341 }
342 
343 void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
344 
345  if (const Stmt *Term = B->getTerminator()) {
346  switch (Term->getStmtClass()) {
347  default:
348  llvm_unreachable("Analysis for this terminator not implemented.");
349 
350  case Stmt::CXXBindTemporaryExprClass:
351  HandleCleanupTemporaryBranch(
352  cast<CXXBindTemporaryExpr>(B->getTerminator().getStmt()), B, Pred);
353  return;
354 
355  // Model static initializers.
356  case Stmt::DeclStmtClass:
357  HandleStaticInit(cast<DeclStmt>(Term), B, Pred);
358  return;
359 
360  case Stmt::BinaryOperatorClass: // '&&' and '||'
361  HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
362  return;
363 
364  case Stmt::BinaryConditionalOperatorClass:
365  case Stmt::ConditionalOperatorClass:
366  HandleBranch(cast<AbstractConditionalOperator>(Term)->getCond(),
367  Term, B, Pred);
368  return;
369 
370  // FIXME: Use constant-folding in CFG construction to simplify this
371  // case.
372 
373  case Stmt::ChooseExprClass:
374  HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
375  return;
376 
377  case Stmt::CXXTryStmtClass: {
378  // Generate a node for each of the successors.
379  // Our logic for EH analysis can certainly be improved.
381  et = B->succ_end(); it != et; ++it) {
382  if (const CFGBlock *succ = *it) {
383  generateNode(BlockEdge(B, succ, Pred->getLocationContext()),
384  Pred->State, Pred);
385  }
386  }
387  return;
388  }
389 
390  case Stmt::DoStmtClass:
391  HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
392  return;
393 
394  case Stmt::CXXForRangeStmtClass:
395  HandleBranch(cast<CXXForRangeStmt>(Term)->getCond(), Term, B, Pred);
396  return;
397 
398  case Stmt::ForStmtClass:
399  HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
400  return;
401 
402  case Stmt::ContinueStmtClass:
403  case Stmt::BreakStmtClass:
404  case Stmt::GotoStmtClass:
405  break;
406 
407  case Stmt::IfStmtClass:
408  HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
409  return;
410 
411  case Stmt::IndirectGotoStmtClass: {
412  // Only 1 successor: the indirect goto dispatch block.
413  assert (B->succ_size() == 1);
414 
416  builder(Pred, B, cast<IndirectGotoStmt>(Term)->getTarget(),
417  *(B->succ_begin()), this);
418 
419  SubEng.processIndirectGoto(builder);
420  return;
421  }
422 
423  case Stmt::ObjCForCollectionStmtClass: {
424  // In the case of ObjCForCollectionStmt, it appears twice in a CFG:
425  //
426  // (1) inside a basic block, which represents the binding of the
427  // 'element' variable to a value.
428  // (2) in a terminator, which represents the branch.
429  //
430  // For (1), subengines will bind a value (i.e., 0 or 1) indicating
431  // whether or not collection contains any more elements. We cannot
432  // just test to see if the element is nil because a container can
433  // contain nil elements.
434  HandleBranch(Term, Term, B, Pred);
435  return;
436  }
437 
438  case Stmt::SwitchStmtClass: {
439  SwitchNodeBuilder builder(Pred, B, cast<SwitchStmt>(Term)->getCond(),
440  this);
441 
442  SubEng.processSwitch(builder);
443  return;
444  }
445 
446  case Stmt::WhileStmtClass:
447  HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
448  return;
449  }
450  }
451 
452  assert (B->succ_size() == 1 &&
453  "Blocks with no terminator should have at most 1 successor.");
454 
455  generateNode(BlockEdge(B, *(B->succ_begin()), Pred->getLocationContext()),
456  Pred->State, Pred);
457 }
458 
459 void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term,
460  const CFGBlock * B, ExplodedNode *Pred) {
461  assert(B->succ_size() == 2);
462  NodeBuilderContext Ctx(*this, B, Pred);
463  ExplodedNodeSet Dst;
464  SubEng.processBranch(Cond, Term, Ctx, Pred, Dst,
465  *(B->succ_begin()), *(B->succ_begin()+1));
466  // Enqueue the new frontier onto the worklist.
467  enqueue(Dst);
468 }
469 
470 void CoreEngine::HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
471  const CFGBlock *B,
472  ExplodedNode *Pred) {
473  assert(B->succ_size() == 2);
474  NodeBuilderContext Ctx(*this, B, Pred);
475  ExplodedNodeSet Dst;
476  SubEng.processCleanupTemporaryBranch(BTE, Ctx, Pred, Dst, *(B->succ_begin()),
477  *(B->succ_begin() + 1));
478  // Enqueue the new frontier onto the worklist.
479  enqueue(Dst);
480 }
481 
482 void CoreEngine::HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
483  ExplodedNode *Pred) {
484  assert(B->succ_size() == 2);
485  NodeBuilderContext Ctx(*this, B, Pred);
486  ExplodedNodeSet Dst;
487  SubEng.processStaticInitializer(DS, Ctx, Pred, Dst,
488  *(B->succ_begin()), *(B->succ_begin()+1));
489  // Enqueue the new frontier onto the worklist.
490  enqueue(Dst);
491 }
492 
493 
494 void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
495  ExplodedNode *Pred) {
496  assert(B);
497  assert(!B->empty());
498 
499  if (StmtIdx == B->size())
500  HandleBlockExit(B, Pred);
501  else {
502  NodeBuilderContext Ctx(*this, B, Pred);
503  SubEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx);
504  }
505 }
506 
507 /// generateNode - Utility method to generate nodes, hook up successors,
508 /// and add nodes to the worklist.
509 void CoreEngine::generateNode(const ProgramPoint &Loc,
511  ExplodedNode *Pred) {
512 
513  bool IsNew;
514  ExplodedNode *Node = G.getNode(Loc, State, false, &IsNew);
515 
516  if (Pred)
517  Node->addPredecessor(Pred, G); // Link 'Node' with its predecessor.
518  else {
519  assert (IsNew);
520  G.addRoot(Node); // 'Node' has no predecessor. Make it a root.
521  }
522 
523  // Only add 'Node' to the worklist if it was freshly generated.
524  if (IsNew) WList->enqueue(Node);
525 }
526 
528  const CFGBlock *Block, unsigned Idx) {
529  assert(Block);
530  assert (!N->isSink());
531 
532  // Check if this node entered a callee.
533  if (N->getLocation().getAs<CallEnter>()) {
534  // Still use the index of the CallExpr. It's needed to create the callee
535  // StackFrameContext.
536  WList->enqueue(N, Block, Idx);
537  return;
538  }
539 
540  // Do not create extra nodes. Move to the next CFG element.
541  if (N->getLocation().getAs<PostInitializer>() ||
543  WList->enqueue(N, Block, Idx+1);
544  return;
545  }
546 
547  if (N->getLocation().getAs<EpsilonPoint>()) {
548  WList->enqueue(N, Block, Idx);
549  return;
550  }
551 
552  if ((*Block)[Idx].getKind() == CFGElement::NewAllocator) {
553  WList->enqueue(N, Block, Idx+1);
554  return;
555  }
556 
557  // At this point, we know we're processing a normal statement.
558  CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>();
559  PostStmt Loc(CS.getStmt(), N->getLocationContext());
560 
561  if (Loc == N->getLocation().withTag(nullptr)) {
562  // Note: 'N' should be a fresh node because otherwise it shouldn't be
563  // a member of Deferred.
564  WList->enqueue(N, Block, Idx+1);
565  return;
566  }
567 
568  bool IsNew;
569  ExplodedNode *Succ = G.getNode(Loc, N->getState(), false, &IsNew);
570  Succ->addPredecessor(N, G);
571 
572  if (IsNew)
573  WList->enqueue(Succ, Block, Idx+1);
574 }
575 
576 ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N) {
577  // Create a CallExitBegin node and enqueue it.
578  const StackFrameContext *LocCtx
579  = cast<StackFrameContext>(N->getLocationContext());
580 
581  // Use the callee location context.
582  CallExitBegin Loc(LocCtx);
583 
584  bool isNew;
585  ExplodedNode *Node = G.getNode(Loc, N->getState(), false, &isNew);
586  Node->addPredecessor(N, G);
587  return isNew ? Node : nullptr;
588 }
589 
590 
592  for (ExplodedNodeSet::iterator I = Set.begin(),
593  E = Set.end(); I != E; ++I) {
594  WList->enqueue(*I);
595  }
596 }
597 
599  const CFGBlock *Block, unsigned Idx) {
600  for (ExplodedNodeSet::iterator I = Set.begin(),
601  E = Set.end(); I != E; ++I) {
602  enqueueStmtNode(*I, Block, Idx);
603  }
604 }
605 
607  for (ExplodedNodeSet::iterator I = Set.begin(), E = Set.end(); I != E; ++I) {
608  ExplodedNode *N = *I;
609  // If we are in an inlined call, generate CallExitBegin node.
610  if (N->getLocationContext()->getParent()) {
611  N = generateCallExitBeginNode(N);
612  if (N)
613  WList->enqueue(N);
614  } else {
615  // TODO: We should run remove dead bindings here.
616  G.addEndOfPath(N);
617  NumPathsExplored++;
618  }
619  }
620 }
621 
622 
623 void NodeBuilder::anchor() { }
624 
626  ProgramStateRef State,
627  ExplodedNode *FromN,
628  bool MarkAsSink) {
629  HasGeneratedNodes = true;
630  bool IsNew;
631  ExplodedNode *N = C.Eng.G.getNode(Loc, State, MarkAsSink, &IsNew);
632  N->addPredecessor(FromN, C.Eng.G);
633  Frontier.erase(FromN);
634 
635  if (!IsNew)
636  return nullptr;
637 
638  if (!MarkAsSink)
639  Frontier.Add(N);
640 
641  return N;
642 }
643 
644 void NodeBuilderWithSinks::anchor() { }
645 
647  if (EnclosingBldr)
648  for (ExplodedNodeSet::iterator I = Frontier.begin(),
649  E = Frontier.end(); I != E; ++I )
650  EnclosingBldr->addNodes(*I);
651 }
652 
653 void BranchNodeBuilder::anchor() { }
654 
656  bool branch,
657  ExplodedNode *NodePred) {
658  // If the branch has been marked infeasible we should not generate a node.
659  if (!isFeasible(branch))
660  return nullptr;
661 
662  ProgramPoint Loc = BlockEdge(C.Block, branch ? DstT:DstF,
663  NodePred->getLocationContext());
664  ExplodedNode *Succ = generateNodeImpl(Loc, State, NodePred);
665  return Succ;
666 }
667 
670  ProgramStateRef St,
671  bool IsSink) {
672  bool IsNew;
673  ExplodedNode *Succ =
674  Eng.G.getNode(BlockEdge(Src, I.getBlock(), Pred->getLocationContext()),
675  St, IsSink, &IsNew);
676  Succ->addPredecessor(Pred, Eng.G);
677 
678  if (!IsNew)
679  return nullptr;
680 
681  if (!IsSink)
682  Eng.WList->enqueue(Succ);
683 
684  return Succ;
685 }
686 
687 
690  ProgramStateRef St) {
691 
692  bool IsNew;
693  ExplodedNode *Succ =
694  Eng.G.getNode(BlockEdge(Src, I.getBlock(), Pred->getLocationContext()),
695  St, false, &IsNew);
696  Succ->addPredecessor(Pred, Eng.G);
697  if (!IsNew)
698  return nullptr;
699 
700  Eng.WList->enqueue(Succ);
701  return Succ;
702 }
703 
704 
707  bool IsSink) {
708  // Get the block for the default case.
709  assert(Src->succ_rbegin() != Src->succ_rend());
710  CFGBlock *DefaultBlock = *Src->succ_rbegin();
711 
712  // Sanity check for default blocks that are unreachable and not caught
713  // by earlier stages.
714  if (!DefaultBlock)
715  return nullptr;
716 
717  bool IsNew;
718  ExplodedNode *Succ =
719  Eng.G.getNode(BlockEdge(Src, DefaultBlock, Pred->getLocationContext()),
720  St, IsSink, &IsNew);
721  Succ->addPredecessor(Pred, Eng.G);
722 
723  if (!IsNew)
724  return nullptr;
725 
726  if (!IsSink)
727  Eng.WList->enqueue(Succ);
728 
729  return Succ;
730 }
succ_reverse_iterator succ_rbegin()
Definition: CFG.h:547
succ_iterator succ_begin()
Definition: CFG.h:542
bool ExecuteWorkList(const LocationContext *L, unsigned Steps, ProgramStateRef InitState)
ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
Definition: CoreEngine.cpp:165
CFGBlock & getEntry()
Definition: CFG.h:863
BlockCounter getBlockCounter() const
Returns the block counter map associated with the worklist unit.
Definition: WorkList.h:52
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
An abstract data type used to count the number of times a given block has been visited along a path a...
Definition: BlockCounter.h:30
unsigned succ_size() const
Definition: CFG.h:552
void enqueue(ExplodedNodeSet &Set)
Enqueue the given set of nodes onto the work list.
Definition: CoreEngine.cpp:591
bool ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps, ProgramStateRef InitState, ExplodedNodeSet &Dst)
Returns true if there is still simulation state on the worklist.
Definition: CoreEngine.cpp:272
Defines the clang::Expr interface and subclasses for C++ expressions.
LineState State
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type...
Definition: CFG.h:87
void addPredecessor(ExplodedNode *V, ExplodedGraph &G)
ExplodedNode * generateNodeImpl(const ProgramPoint &PP, ProgramStateRef State, ExplodedNode *Pred, bool MarkAsSink=false)
Definition: CoreEngine.cpp:625
ExplodedNode * generateCaseStmtNode(const iterator &I, ProgramStateRef State)
Definition: CoreEngine.cpp:689
Represents binding an expression to a temporary.
Definition: ExprCXX.h:1032
ExplodedNode * getFirstPred()
const LocationContext * getLocationContext() const
const CFGBlock * getBlock() const
Returns the CFGblock associated with the worklist unit.
Definition: WorkList.h:55
std::vector< bool > & Stack
const CFGBlock * getDst() const
Definition: ProgramPoint.h:460
STATISTIC(NumSteps,"The # of steps executed.")
const ProgramStateRef & getState() const
void Add(ExplodedNode *N)
void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx)
Enqueue a single node created as a result of statement processing.
Definition: CoreEngine.cpp:527
T castAs() const
Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type...
Definition: ProgramPoint.h:116
unsigned getBlockID() const
Definition: CFG.h:639
Kind getKind() const
Definition: ProgramPoint.h:136
ExplodedNode * generateNode(const iterator &I, ProgramStateRef State, bool isSink=false)
Definition: CoreEngine.cpp:669
unsigned getIndex() const
Return the index within the CFGBlock for the worklist unit.
Definition: WorkList.h:58
void enqueueEndOfFunction(ExplodedNodeSet &Set)
enqueue the nodes corresponding to the end of function onto the end of path / work list...
Definition: CoreEngine.cpp:606
CFGTerminator getTerminator()
Definition: CFG.h:623
ExplodedNode * getNode() const
Returns the node associated with the worklist unit.
Definition: WorkList.h:49
const StackFrameContext * getCurrentStackFrame() const
Optional< CFGElement > getFirstElement() const
Definition: ProgramPoint.h:205
virtual bool hasWork() const =0
void dispatchWorkItem(ExplodedNode *Pred, ProgramPoint Loc, const WorkListUnit &WU)
Definition: CoreEngine.cpp:229
const Stmt * getStmt() const
Definition: CFG.h:119
ProgramPoint withTag(const ProgramPointTag *tag) const
Definition: ProgramPoint.h:108
const Decl * getDecl() const
virtual WorkListUnit dequeue()=0
succ_iterator succ_end()
Definition: CFG.h:543
static WorkList * makeDFS()
Definition: CoreEngine.cpp:105
AdjacentBlocks::const_iterator const_succ_iterator
Definition: CFG.h:528
ast_type_traits::DynTypedNode Node
const LocationContext * getParent() const
ExplodedNode * generateDefaultCaseNode(ProgramStateRef State, bool isSink=false)
Definition: CoreEngine.cpp:706
const LocationContext * getLocationContext() const
Definition: ProgramPoint.h:155
virtual bool visitItemsInWorkList(Visitor &V)=0
This node builder keeps track of the generated sink nodes.
Definition: CoreEngine.h:309
unsigned size() const
Definition: CFG.h:516
static WorkList * makeBFSBlockDFSContents()
Definition: CoreEngine.cpp:156
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
Definition: ProgramPoint.h:127
Stmt * getStmt()
Definition: CFG.h:311
NodeVector::iterator eop_iterator
const CFGBlock * getBlock() const
Definition: CoreEngine.h:517
ExplodedNode * generateNode(ProgramStateRef State, bool branch, ExplodedNode *Pred)
Definition: CoreEngine.cpp:655
static Decl::Kind getKind(const Decl *D)
Definition: DeclBase.cpp:739
virtual void enqueue(const WorkListUnit &U)=0
bool empty() const
Definition: CFG.h:517
unsigned getNumBlockIDs() const
Definition: CFG.h:932
const CFGBlock * getBlock() const
Definition: ProgramPoint.h:201
static WorkList * makeBFS()
Definition: CoreEngine.cpp:106
CFGBlock & getExit()
Definition: CFG.h:865