Clang Project

clang_source_code/lib/StaticAnalyzer/Core/CoreEngine.cpp
1//===- CoreEngine.cpp - Path-Sensitive Dataflow Engine --------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9//  This file defines a generic engine for intraprocedural, path-sensitive,
10//  dataflow analysis via graph reachability engine.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h"
15#include "clang/AST/Expr.h"
16#include "clang/AST/ExprCXX.h"
17#include "clang/AST/Stmt.h"
18#include "clang/AST/StmtCXX.h"
19#include "clang/Analysis/AnalysisDeclContext.h"
20#include "clang/Analysis/CFG.h"
21#include "clang/Analysis/ProgramPoint.h"
22#include "clang/Basic/LLVM.h"
23#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
24#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h"
25#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
26#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h"
27#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
28#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h"
29#include "llvm/ADT/Optional.h"
30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/Statistic.h"
32#include "llvm/Support/Casting.h"
33#include "llvm/Support/ErrorHandling.h"
34#include <algorithm>
35#include <cassert>
36#include <memory>
37#include <utility>
38
39using namespace clang;
40using namespace ento;
41
42#define DEBUG_TYPE "CoreEngine"
43
44STATISTIC(NumSteps,
45            "The # of steps executed.");
46STATISTIC(NumReachedMaxSteps,
47            "The # of times we reached the max number of steps.");
48STATISTIC(NumPathsExplored,
49            "The # of paths explored by the analyzer.");
50
51//===----------------------------------------------------------------------===//
52// Core analysis engine.
53//===----------------------------------------------------------------------===//
54
55static std::unique_ptr<WorkListgenerateWorkList(AnalyzerOptions &Opts,
56                                                  SubEngine &subengine) {
57  switch (Opts.getExplorationStrategy()) {
58    case ExplorationStrategyKind::DFS:
59      return WorkList::makeDFS();
60    case ExplorationStrategyKind::BFS:
61      return WorkList::makeBFS();
62    case ExplorationStrategyKind::BFSBlockDFSContents:
63      return WorkList::makeBFSBlockDFSContents();
64    case ExplorationStrategyKind::UnexploredFirst:
65      return WorkList::makeUnexploredFirst();
66    case ExplorationStrategyKind::UnexploredFirstQueue:
67      return WorkList::makeUnexploredFirstPriorityQueue();
68    case ExplorationStrategyKind::UnexploredFirstLocationQueue:
69      return WorkList::makeUnexploredFirstPriorityLocationQueue();
70  }
71  llvm_unreachable("Unknown AnalyzerOptions::ExplorationStrategyKind");
72}
73
74CoreEngine::CoreEngine(SubEngine &subengineFunctionSummariesTy *FS,
75                       AnalyzerOptions &Opts)
76    : SubEng(subengine), WList(generateWorkList(Optssubengine)),
77      BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {}
78
79/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
80bool CoreEngine::ExecuteWorkList(const LocationContext *Lunsigned Steps,
81                                   ProgramStateRef InitState) {
82  if (G.num_roots() == 0) { // Initialize the analysis by constructing
83    // the root if none exists.
84
85    const CFGBlock *Entry = &(L->getCFG()->getEntry());
86
87     (0) . __assert_fail ("Entry->empty() && \"Entry block must be empty.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 87, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Entry->empty() && "Entry block must be empty.");
88
89     (0) . __assert_fail ("Entry->succ_size() == 1 && \"Entry block must have 1 successor.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 89, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Entry->succ_size() == 1 && "Entry block must have 1 successor.");
90
91    // Mark the entry block as visited.
92    FunctionSummaries->markVisitedBasicBlock(Entry->getBlockID(),
93                                             L->getDecl(),
94                                             L->getCFG()->getNumBlockIDs());
95
96    // Get the solitary successor.
97    const CFGBlock *Succ = *(Entry->succ_begin());
98
99    // Construct an edge representing the
100    // starting location in the function.
101    BlockEdge StartLoc(EntrySuccL);
102
103    // Set the current block counter to being empty.
104    WList->setBlockCounter(BCounterFactory.GetEmptyCounter());
105
106    if (!InitState)
107      InitState = SubEng.getInitialState(L);
108
109    bool IsNew;
110    ExplodedNode *Node = G.getNode(StartLoc, InitState, false, &IsNew);
111    assert(IsNew);
112    G.addRoot(Node);
113
114    NodeBuilderContext BuilderCtx(*thisStartLoc.getDst(), Node);
115    ExplodedNodeSet DstBegin;
116    SubEng.processBeginOfFunction(BuilderCtxNodeDstBeginStartLoc);
117
118    enqueue(DstBegin);
119  }
120
121  // Check if we have a steps limit
122  bool UnlimitedSteps = Steps == 0;
123  // Cap our pre-reservation in the event that the user specifies
124  // a very large number of maximum steps.
125  const unsigned PreReservationCap = 4000000;
126  if(!UnlimitedSteps)
127    G.reserve(std::min(Steps,PreReservationCap));
128
129  while (WList->hasWork()) {
130    if (!UnlimitedSteps) {
131      if (Steps == 0) {
132        NumReachedMaxSteps++;
133        break;
134      }
135      --Steps;
136    }
137
138    NumSteps++;
139
140    const WorkListUnitWU = WList->dequeue();
141
142    // Set the current block counter.
143    WList->setBlockCounter(WU.getBlockCounter());
144
145    // Retrieve the node.
146    ExplodedNode *Node = WU.getNode();
147
148    dispatchWorkItem(NodeNode->getLocation(), WU);
149  }
150  SubEng.processEndWorklist();
151  return WList->hasWork();
152}
153
154void CoreEngine::dispatchWorkItem(ExplodedNodePredProgramPoint Loc,
155                                  const WorkListUnitWU) {
156  // Dispatch on the location type.
157  switch (Loc.getKind()) {
158    case ProgramPoint::BlockEdgeKind:
159      HandleBlockEdge(Loc.castAs<BlockEdge>(), Pred);
160      break;
161
162    case ProgramPoint::BlockEntranceKind:
163      HandleBlockEntrance(Loc.castAs<BlockEntrance>(), Pred);
164      break;
165
166    case ProgramPoint::BlockExitKind:
167       (0) . __assert_fail ("false && \"BlockExit location never occur in forward analysis.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 167, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(false && "BlockExit location never occur in forward analysis.");
168      break;
169
170    case ProgramPoint::CallEnterKind:
171      HandleCallEnter(Loc.castAs<CallEnter>(), Pred);
172      break;
173
174    case ProgramPoint::CallExitBeginKind:
175      SubEng.processCallExit(Pred);
176      break;
177
178    case ProgramPoint::EpsilonKind: {
179       (0) . __assert_fail ("Pred->hasSinglePred() && \"Assume epsilon has exactly one predecessor by construction\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 180, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Pred->hasSinglePred() &&
180 (0) . __assert_fail ("Pred->hasSinglePred() && \"Assume epsilon has exactly one predecessor by construction\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 180, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">             "Assume epsilon has exactly one predecessor by construction");
181      ExplodedNode *PNode = Pred->getFirstPred();
182      dispatchWorkItem(PredPNode->getLocation(), WU);
183      break;
184    }
185    default:
186      () || Loc.getAs() || Loc.getAs() || Loc.getAs() || Loc.getAs() || Loc.getAs()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 191, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Loc.getAs<PostStmt>() ||
187() || Loc.getAs() || Loc.getAs() || Loc.getAs() || Loc.getAs() || Loc.getAs()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 191, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">             Loc.getAs<PostInitializer>() ||
188() || Loc.getAs() || Loc.getAs() || Loc.getAs() || Loc.getAs() || Loc.getAs()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 191, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">             Loc.getAs<PostImplicitCall>() ||
189() || Loc.getAs() || Loc.getAs() || Loc.getAs() || Loc.getAs() || Loc.getAs()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 191, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">             Loc.getAs<CallExitEnd>() ||
190() || Loc.getAs() || Loc.getAs() || Loc.getAs() || Loc.getAs() || Loc.getAs()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 191, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">             Loc.getAs<LoopExit>() ||
191() || Loc.getAs() || Loc.getAs() || Loc.getAs() || Loc.getAs() || Loc.getAs()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 191, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">             Loc.getAs<PostAllocatorCall>());
192      HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
193      break;
194  }
195}
196
197bool CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L,
198                                                 unsigned Steps,
199                                                 ProgramStateRef InitState,
200                                                 ExplodedNodeSet &Dst) {
201  bool DidNotFinish = ExecuteWorkList(L, Steps, InitState);
202  for (ExplodedGraph::eop_iterator I = G.eop_begin(), E = G.eop_end(); I != E;
203       ++I) {
204    Dst.Add(*I);
205  }
206  return DidNotFinish;
207}
208
209void CoreEngine::HandleBlockEdge(const BlockEdge &LExplodedNode *Pred) {
210  const CFGBlock *Blk = L.getDst();
211  NodeBuilderContext BuilderCtx(*thisBlkPred);
212
213  // Mark this block as visited.
214  const LocationContext *LC = Pred->getLocationContext();
215  FunctionSummaries->markVisitedBasicBlock(Blk->getBlockID(),
216                                           LC->getDecl(),
217                                           LC->getCFG()->getNumBlockIDs());
218
219  // Check if we are entering the EXIT block.
220  if (Blk == &(L.getLocationContext()->getCFG()->getExit())) {
221     (0) . __assert_fail ("L.getLocationContext()->getCFG()->getExit().empty() && \"EXIT block cannot contain Stmts.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 222, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(L.getLocationContext()->getCFG()->getExit().empty() &&
222 (0) . __assert_fail ("L.getLocationContext()->getCFG()->getExit().empty() && \"EXIT block cannot contain Stmts.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 222, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">           "EXIT block cannot contain Stmts.");
223
224    // Get return statement..
225    const ReturnStmt *RS = nullptr;
226    if (!L.getSrc()->empty()) {
227      CFGElement LastElement = L.getSrc()->back();
228      if (Optional<CFGStmt> LastStmt = LastElement.getAs<CFGStmt>()) {
229        RS = dyn_cast<ReturnStmt>(LastStmt->getStmt());
230      } else if (Optional<CFGAutomaticObjDtor> AutoDtor =
231                 LastElement.getAs<CFGAutomaticObjDtor>()) {
232        RS = dyn_cast<ReturnStmt>(AutoDtor->getTriggerStmt());
233      }
234    }
235
236    // Process the final state transition.
237    SubEng.processEndOfFunction(BuilderCtxPredRS);
238
239    // This path is done. Don't enqueue any more nodes.
240    return;
241  }
242
243  // Call into the SubEngine to process entering the CFGBlock.
244  ExplodedNodeSet dstNodes;
245  BlockEntrance BE(BlkPred->getLocationContext());
246  NodeBuilderWithSinks nodeBuilder(PreddstNodesBuilderCtxBE);
247  SubEng.processCFGBlockEntrance(LnodeBuilderPred);
248
249  // Auto-generate a node.
250  if (!nodeBuilder.hasGeneratedNodes()) {
251    nodeBuilder.generateNode(Pred->State, Pred);
252  }
253
254  // Enqueue nodes onto the worklist.
255  enqueue(dstNodes);
256}
257
258void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
259                                       ExplodedNode *Pred) {
260  // Increment the block counter.
261  const LocationContext *LC = Pred->getLocationContext();
262  unsigned BlockId = L.getBlock()->getBlockID();
263  BlockCounter Counter = WList->getBlockCounter();
264  Counter = BCounterFactory.IncrementCount(CounterLC->getStackFrame(),
265                                           BlockId);
266  WList->setBlockCounter(Counter);
267
268  // Process the entrance of the block.
269  if (Optional<CFGElement> E = L.getFirstElement()) {
270    NodeBuilderContext Ctx(*thisL.getBlock(), Pred);
271    SubEng.processCFGElement(*E, Pred, 0, &Ctx);
272  }
273  else
274    HandleBlockExit(L.getBlock(), Pred);
275}
276
277void CoreEngine::HandleBlockExit(const CFGBlock * BExplodedNode *Pred) {
278  if (const Stmt *Term = B->getTerminator()) {
279    switch (Term->getStmtClass()) {
280      default:
281        llvm_unreachable("Analysis for this terminator not implemented.");
282
283      case Stmt::CXXBindTemporaryExprClass:
284        HandleCleanupTemporaryBranch(
285            cast<CXXBindTemporaryExpr>(B->getTerminator().getStmt()), BPred);
286        return;
287
288      // Model static initializers.
289      case Stmt::DeclStmtClass:
290        HandleStaticInit(cast<DeclStmt>(Term), BPred);
291        return;
292
293      case Stmt::BinaryOperatorClass: // '&&' and '||'
294        HandleBranch(cast<BinaryOperator>(Term)->getLHS(), TermBPred);
295        return;
296
297      case Stmt::BinaryConditionalOperatorClass:
298      case Stmt::ConditionalOperatorClass:
299        HandleBranch(cast<AbstractConditionalOperator>(Term)->getCond(),
300                     TermBPred);
301        return;
302
303        // FIXME: Use constant-folding in CFG construction to simplify this
304        // case.
305
306      case Stmt::ChooseExprClass:
307        HandleBranch(cast<ChooseExpr>(Term)->getCond(), TermBPred);
308        return;
309
310      case Stmt::CXXTryStmtClass:
311        // Generate a node for each of the successors.
312        // Our logic for EH analysis can certainly be improved.
313        for (CFGBlock::const_succ_iterator it = B->succ_begin(),
314             et = B->succ_end(); it != et; ++it) {
315          if (const CFGBlock *succ = *it) {
316            generateNode(BlockEdge(BsuccPred->getLocationContext()),
317                         Pred->State, Pred);
318          }
319        }
320        return;
321
322      case Stmt::DoStmtClass:
323        HandleBranch(cast<DoStmt>(Term)->getCond(), TermBPred);
324        return;
325
326      case Stmt::CXXForRangeStmtClass:
327        HandleBranch(cast<CXXForRangeStmt>(Term)->getCond(), TermBPred);
328        return;
329
330      case Stmt::ForStmtClass:
331        HandleBranch(cast<ForStmt>(Term)->getCond(), TermBPred);
332        return;
333
334      case Stmt::ContinueStmtClass:
335      case Stmt::BreakStmtClass:
336      case Stmt::GotoStmtClass:
337        break;
338
339      case Stmt::IfStmtClass:
340        HandleBranch(cast<IfStmt>(Term)->getCond(), TermBPred);
341        return;
342
343      case Stmt::IndirectGotoStmtClass: {
344        // Only 1 successor: the indirect goto dispatch block.
345        succ_size() == 1", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 345, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(B->succ_size() == 1);
346
347        IndirectGotoNodeBuilder
348           builder(PredB, cast<IndirectGotoStmt>(Term)->getTarget(),
349                   *(B->succ_begin()), this);
350
351        SubEng.processIndirectGoto(builder);
352        return;
353      }
354
355      case Stmt::ObjCForCollectionStmtClass:
356        // In the case of ObjCForCollectionStmt, it appears twice in a CFG:
357        //
358        //  (1) inside a basic block, which represents the binding of the
359        //      'element' variable to a value.
360        //  (2) in a terminator, which represents the branch.
361        //
362        // For (1), subengines will bind a value (i.e., 0 or 1) indicating
363        // whether or not collection contains any more elements.  We cannot
364        // just test to see if the element is nil because a container can
365        // contain nil elements.
366        HandleBranch(TermTermBPred);
367        return;
368
369      case Stmt::SwitchStmtClass: {
370        SwitchNodeBuilder builder(PredB, cast<SwitchStmt>(Term)->getCond(),
371                                    this);
372
373        SubEng.processSwitch(builder);
374        return;
375      }
376
377      case Stmt::WhileStmtClass:
378        HandleBranch(cast<WhileStmt>(Term)->getCond(), TermBPred);
379        return;
380    }
381  }
382
383   (0) . __assert_fail ("B->succ_size() == 1 && \"Blocks with no terminator should have at most 1 successor.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 384, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(B->succ_size() == 1 &&
384 (0) . __assert_fail ("B->succ_size() == 1 && \"Blocks with no terminator should have at most 1 successor.\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 384, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">         "Blocks with no terminator should have at most 1 successor.");
385
386  generateNode(BlockEdge(B, *(B->succ_begin()), Pred->getLocationContext()),
387               Pred->State, Pred);
388}
389
390void CoreEngine::HandleCallEnter(const CallEnter &CEExplodedNode *Pred) {
391  NodeBuilderContext BuilderCtx(*thisCE.getEntry(), Pred);
392  SubEng.processCallEnter(BuilderCtxCEPred);
393}
394
395void CoreEngine::HandleBranch(const Stmt *Condconst Stmt *Term,
396                                const CFGBlock * BExplodedNode *Pred) {
397  succ_size() == 2", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 397, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(B->succ_size() == 2);
398  NodeBuilderContext Ctx(*thisBPred);
399  ExplodedNodeSet Dst;
400  SubEng.processBranch(CondCtxPredDst, *(B->succ_begin()),
401                       *(B->succ_begin() + 1));
402  // Enqueue the new frontier onto the worklist.
403  enqueue(Dst);
404}
405
406void CoreEngine::HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
407                                              const CFGBlock *B,
408                                              ExplodedNode *Pred) {
409  succ_size() == 2", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 409, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(B->succ_size() == 2);
410  NodeBuilderContext Ctx(*thisBPred);
411  ExplodedNodeSet Dst;
412  SubEng.processCleanupTemporaryBranch(BTECtxPredDst, *(B->succ_begin()),
413                                       *(B->succ_begin() + 1));
414  // Enqueue the new frontier onto the worklist.
415  enqueue(Dst);
416}
417
418void CoreEngine::HandleStaticInit(const DeclStmt *DSconst CFGBlock *B,
419                                  ExplodedNode *Pred) {
420  succ_size() == 2", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 420, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(B->succ_size() == 2);
421  NodeBuilderContext Ctx(*thisBPred);
422  ExplodedNodeSet Dst;
423  SubEng.processStaticInitializer(DSCtxPredDst,
424                                  *(B->succ_begin()), *(B->succ_begin()+1));
425  // Enqueue the new frontier onto the worklist.
426  enqueue(Dst);
427}
428
429void CoreEngine::HandlePostStmt(const CFGBlock *Bunsigned StmtIdx,
430                                ExplodedNode *Pred) {
431  assert(B);
432  empty()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 432, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!B->empty());
433
434  if (StmtIdx == B->size())
435    HandleBlockExit(BPred);
436  else {
437    NodeBuilderContext Ctx(*thisBPred);
438    SubEng.processCFGElement((*B)[StmtIdx], PredStmtIdx, &Ctx);
439  }
440}
441
442/// generateNode - Utility method to generate nodes, hook up successors,
443///  and add nodes to the worklist.
444void CoreEngine::generateNode(const ProgramPoint &Loc,
445                              ProgramStateRef State,
446                              ExplodedNode *Pred) {
447  bool IsNew;
448  ExplodedNode *Node = G.getNode(Loc, State, false, &IsNew);
449
450  if (Pred)
451    Node->addPredecessor(Pred, G); // Link 'Node' with its predecessor.
452  else {
453    assert(IsNew);
454    G.addRoot(Node); // 'Node' has no predecessor.  Make it a root.
455  }
456
457  // Only add 'Node' to the worklist if it was freshly generated.
458  if (IsNewWList->enqueue(Node);
459}
460
461void CoreEngine::enqueueStmtNode(ExplodedNode *N,
462                                 const CFGBlock *Blockunsigned Idx) {
463  assert(Block);
464  isSink()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 464, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(!N->isSink());
465
466  // Check if this node entered a callee.
467  if (N->getLocation().getAs<CallEnter>()) {
468    // Still use the index of the CallExpr. It's needed to create the callee
469    // StackFrameContext.
470    WList->enqueue(NBlockIdx);
471    return;
472  }
473
474  // Do not create extra nodes. Move to the next CFG element.
475  if (N->getLocation().getAs<PostInitializer>() ||
476      N->getLocation().getAs<PostImplicitCall>()||
477      N->getLocation().getAs<LoopExit>()) {
478    WList->enqueue(NBlockIdx+1);
479    return;
480  }
481
482  if (N->getLocation().getAs<EpsilonPoint>()) {
483    WList->enqueue(NBlockIdx);
484    return;
485  }
486
487  if ((*Block)[Idx].getKind() == CFGElement::NewAllocator) {
488    WList->enqueue(NBlockIdx+1);
489    return;
490  }
491
492  // At this point, we know we're processing a normal statement.
493  CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>();
494  PostStmt Loc(CS.getStmt(), N->getLocationContext());
495
496  if (Loc == N->getLocation().withTag(nullptr)) {
497    // Note: 'N' should be a fresh node because otherwise it shouldn't be
498    // a member of Deferred.
499    WList->enqueue(NBlockIdx+1);
500    return;
501  }
502
503  bool IsNew;
504  ExplodedNode *Succ = G.getNode(Loc, N->getState(), false, &IsNew);
505  Succ->addPredecessor(N, G);
506
507  if (IsNew)
508    WList->enqueue(SuccBlockIdx+1);
509}
510
511ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N,
512                                                    const ReturnStmt *RS) {
513  // Create a CallExitBegin node and enqueue it.
514  const auto *LocCtx = cast<StackFrameContext>(N->getLocationContext());
515
516  // Use the callee location context.
517  CallExitBegin Loc(LocCtx, RS);
518
519  bool isNew;
520  ExplodedNode *Node = G.getNode(Loc, N->getState(), false, &isNew);
521  Node->addPredecessor(N, G);
522  return isNew ? Node : nullptr;
523}
524
525void CoreEngine::enqueue(ExplodedNodeSet &Set) {
526  for (const auto I : Set)
527    WList->enqueue(I);
528}
529
530void CoreEngine::enqueue(ExplodedNodeSet &Set,
531                         const CFGBlock *Blockunsigned Idx) {
532  for (const auto I : Set)
533    enqueueStmtNode(I, Block, Idx);
534}
535
536void CoreEngine::enqueueEndOfFunction(ExplodedNodeSet &Setconst ReturnStmt *RS) {
537  for (auto I : Set) {
538    // If we are in an inlined call, generate CallExitBegin node.
539    if (I->getLocationContext()->getParent()) {
540      I = generateCallExitBeginNode(I, RS);
541      if (I)
542        WList->enqueue(I);
543    } else {
544      // TODO: We should run remove dead bindings here.
545      G.addEndOfPath(I);
546      NumPathsExplored++;
547    }
548  }
549}
550
551void NodeBuilder::anchor() {}
552
553ExplodedNodeNodeBuilder::generateNodeImpl(const ProgramPoint &Loc,
554                                            ProgramStateRef State,
555                                            ExplodedNode *FromN,
556                                            bool MarkAsSink) {
557  HasGeneratedNodes = true;
558  bool IsNew;
559  ExplodedNode *N = C.Eng.G.getNode(Loc, State, MarkAsSink, &IsNew);
560  N->addPredecessor(FromNC.Eng.G);
561  Frontier.erase(FromN);
562
563  if (!IsNew)
564    return nullptr;
565
566  if (!MarkAsSink)
567    Frontier.Add(N);
568
569  return N;
570}
571
572void NodeBuilderWithSinks::anchor() {}
573
574StmtNodeBuilder::~StmtNodeBuilder() {
575  if (EnclosingBldr)
576    for (const auto I : Frontier)
577      EnclosingBldr->addNodes(I);
578}
579
580void BranchNodeBuilder::anchor() {}
581
582ExplodedNode *BranchNodeBuilder::generateNode(ProgramStateRef State,
583                                              bool branch,
584                                              ExplodedNode *NodePred) {
585  // If the branch has been marked infeasible we should not generate a node.
586  if (!isFeasible(branch))
587    return nullptr;
588
589  ProgramPoint Loc = BlockEdge(C.Blockbranch ? DstT:DstF,
590                               NodePred->getLocationContext());
591  ExplodedNode *Succ = generateNodeImpl(Loc, State, NodePred);
592  return Succ;
593}
594
595ExplodedNode*
596IndirectGotoNodeBuilder::generateNode(const iterator &I,
597                                      ProgramStateRef St,
598                                      bool IsSink) {
599  bool IsNew;
600  ExplodedNode *Succ =
601      Eng.G.getNode(BlockEdge(Src, I.getBlock(), Pred->getLocationContext()),
602                    St, IsSink, &IsNew);
603  Succ->addPredecessor(PredEng.G);
604
605  if (!IsNew)
606    return nullptr;
607
608  if (!IsSink)
609    Eng.WList->enqueue(Succ);
610
611  return Succ;
612}
613
614ExplodedNode*
615SwitchNodeBuilder::generateCaseStmtNode(const iterator &I,
616                                        ProgramStateRef St) {
617  bool IsNew;
618  ExplodedNode *Succ =
619      Eng.G.getNode(BlockEdge(Src, I.getBlock(), Pred->getLocationContext()),
620                    St, false, &IsNew);
621  Succ->addPredecessor(PredEng.G);
622  if (!IsNew)
623    return nullptr;
624
625  Eng.WList->enqueue(Succ);
626  return Succ;
627}
628
629ExplodedNode*
630SwitchNodeBuilder::generateDefaultCaseNode(ProgramStateRef St,
631                                           bool IsSink) {
632  // Get the block for the default case.
633  succ_rbegin() != Src->succ_rend()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp", 633, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(Src->succ_rbegin() != Src->succ_rend());
634  CFGBlock *DefaultBlock = *Src->succ_rbegin();
635
636  // Sanity check for default blocks that are unreachable and not caught
637  // by earlier stages.
638  if (!DefaultBlock)
639    return nullptr;
640
641  bool IsNew;
642  ExplodedNode *Succ =
643      Eng.G.getNode(BlockEdge(Src, DefaultBlock, Pred->getLocationContext()),
644                    St, IsSink, &IsNew);
645  Succ->addPredecessor(PredEng.G);
646
647  if (!IsNew)
648    return nullptr;
649
650  if (!IsSink)
651    Eng.WList->enqueue(Succ);
652
653  return Succ;
654}
655
clang::ento::CoreEngine::ExecuteWorkList
clang::ento::CoreEngine::dispatchWorkItem
clang::ento::CoreEngine::ExecuteWorkListWithInitialState
clang::ento::CoreEngine::HandleBlockEdge
clang::ento::CoreEngine::HandleBlockEntrance
clang::ento::CoreEngine::HandleBlockExit
clang::ento::CoreEngine::HandleCallEnter
clang::ento::CoreEngine::HandleBranch
clang::ento::CoreEngine::HandleCleanupTemporaryBranch
clang::ento::CoreEngine::HandleStaticInit
clang::ento::CoreEngine::HandlePostStmt
clang::ento::CoreEngine::generateNode
clang::ento::CoreEngine::enqueueStmtNode
clang::ento::CoreEngine::generateCallExitBeginNode
clang::ento::CoreEngine::enqueue
clang::ento::CoreEngine::enqueue
clang::ento::CoreEngine::enqueueEndOfFunction
clang::ento::NodeBuilder::anchor
clang::ento::NodeBuilder::generateNodeImpl
clang::ento::NodeBuilderWithSinks::anchor
clang::ento::BranchNodeBuilder::anchor
clang::ento::BranchNodeBuilder::generateNode
clang::ento::IndirectGotoNodeBuilder::generateNode
clang::ento::SwitchNodeBuilder::generateCaseStmtNode
clang::ento::SwitchNodeBuilder::generateDefaultCaseNode