clang 23.0.0git
CoreEngine.cpp
Go to the documentation of this file.
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
16#include "clang/AST/Expr.h"
17#include "clang/AST/ExprCXX.h"
18#include "clang/AST/Stmt.h"
19#include "clang/AST/StmtCXX.h"
21#include "clang/Analysis/CFG.h"
23#include "clang/Basic/LLVM.h"
31#include "llvm/Support/ErrorHandling.h"
32#include "llvm/Support/FormatVariadic.h"
33#include "llvm/Support/TimeProfiler.h"
34#include <algorithm>
35#include <cassert>
36#include <memory>
37#include <optional>
38#include <utility>
39
40using namespace clang;
41using namespace ento;
42
43#define DEBUG_TYPE "CoreEngine"
44
45STAT_COUNTER(NumSteps, "The # of steps executed.");
46STAT_COUNTER(NumSTUSteps, "The # of STU steps executed.");
47STAT_COUNTER(NumCTUSteps, "The # of CTU steps executed.");
48ALWAYS_ENABLED_STATISTIC(NumReachedMaxSteps,
49 "The # of times we reached the max number of steps.");
50STAT_COUNTER(NumPathsExplored, "The # of paths explored by the analyzer.");
51
52//===----------------------------------------------------------------------===//
53// Core analysis engine.
54//===----------------------------------------------------------------------===//
55
73
75 AnalyzerOptions &Opts)
76 : ExprEng(exprengine), WList(generateWorkList(Opts)),
77 CTUWList(Opts.IsNaiveCTUEnabled ? generateWorkList(Opts) : nullptr),
78 BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {}
79
80void CoreEngine::setBlockCounter(BlockCounter C) {
81 WList->setBlockCounter(C);
82 if (CTUWList)
83 CTUWList->setBlockCounter(C);
84}
85
86/// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
87bool CoreEngine::ExecuteWorkList(const StackFrame *SF, unsigned MaxSteps,
88 ProgramStateRef InitState) {
89 if (G.empty()) {
90 assert(!G.getRoot() && "empty graph must not have a root node");
91 // Initialize the analysis by constructing the root if there are no nodes.
92
93 const CFGBlock *Entry = &(SF->getCFG()->getEntry());
94
95 assert(Entry->empty() && "Entry block must be empty.");
96
97 assert(Entry->succ_size() == 1 && "Entry block must have 1 successor.");
98
99 // Mark the entry block as visited.
100 FunctionSummaries->markVisitedBasicBlock(Entry->getBlockID(), SF->getDecl(),
101 SF->getCFG()->getNumBlockIDs());
102
103 // Get the solitary successor.
104 const CFGBlock *Succ = *(Entry->succ_begin());
105
106 // Construct an edge representing the
107 // starting location in the function.
108 BlockEdge StartLoc(Entry, Succ, SF);
109
110 // Set the current block counter to being empty.
111 setBlockCounter(BCounterFactory.GetEmptyCounter());
112
113 if (!InitState)
114 InitState = ExprEng.getInitialState(SF);
115
116 bool IsNew;
117 ExplodedNode *Node = G.getNode(StartLoc, InitState, false, &IsNew);
118 assert(IsNew);
119 G.designateAsRoot(Node);
120
121 ExprEng.setCurrStackFrameAndBlock(Node->getStackFrame(), Succ);
122
123 ExplodedNodeSet DstBegin;
124 ExprEng.processBeginOfFunction(Node, DstBegin, StartLoc);
125
126 enqueue(DstBegin);
127 }
128
129 // Check if we have a steps limit
130 bool UnlimitedSteps = MaxSteps == 0;
131
132 // Cap our pre-reservation in the event that the user specifies
133 // a very large number of maximum steps.
134 const unsigned PreReservationCap = 4000000;
135 if(!UnlimitedSteps)
136 G.reserve(std::min(MaxSteps, PreReservationCap));
137
138 auto ProcessWList = [this, UnlimitedSteps](unsigned MaxSteps) {
139 unsigned Steps = MaxSteps;
140 while (WList->hasWork()) {
141 if (!UnlimitedSteps) {
142 if (Steps == 0) {
143 NumReachedMaxSteps++;
144 break;
145 }
146 --Steps;
147 }
148
149 NumSteps++;
150
151 const WorkListUnit &WU = WList->dequeue();
152
153 // Set the current block counter.
154 setBlockCounter(WU.getBlockCounter());
155
156 // Retrieve the node.
157 ExplodedNode *Node = WU.getNode();
158
159 dispatchWorkItem(Node, Node->getLocation(), WU);
160 }
161 return MaxSteps - Steps;
162 };
163 const unsigned STUSteps = ProcessWList(MaxSteps);
164
165 if (CTUWList) {
166 NumSTUSteps += STUSteps;
167 const unsigned MinCTUSteps =
168 this->ExprEng.getAnalysisManager().options.CTUMaxNodesMin;
169 const unsigned Pct =
170 this->ExprEng.getAnalysisManager().options.CTUMaxNodesPercentage;
171 unsigned MaxCTUSteps = std::max(STUSteps * Pct / 100, MinCTUSteps);
172
173 WList = std::move(CTUWList);
174 const unsigned CTUSteps = ProcessWList(MaxCTUSteps);
175 NumCTUSteps += CTUSteps;
176 }
177
178 ExprEng.processEndWorklist();
179 return WList->hasWork();
180}
181
182static std::string timeTraceScopeName(const ProgramPoint &Loc) {
183 if (llvm::timeTraceProfilerEnabled()) {
184 return llvm::formatv("dispatchWorkItem {0}",
186 .str();
187 }
188 return "";
189}
190
191static llvm::TimeTraceMetadata timeTraceMetadata(const ExplodedNode *Pred,
192 const ProgramPoint &Loc) {
193 // If time-trace profiler is not enabled, this function is never called.
194 assert(llvm::timeTraceProfilerEnabled());
195 std::string Detail = "";
196 if (const auto SP = Loc.getAs<StmtPoint>()) {
197 if (const Stmt *S = SP->getStmt())
198 Detail = S->getStmtClassName();
199 }
200 auto SLoc = Loc.getSourceLocation();
201 if (!SLoc)
202 return llvm::TimeTraceMetadata{std::move(Detail), ""};
203 const auto &SM = Pred->getStackFrame()
205 ->getASTContext()
207 auto Line = SM.getPresumedLineNumber(*SLoc);
208 auto Fname = SM.getFilename(*SLoc);
209 return llvm::TimeTraceMetadata{std::move(Detail), Fname.str(),
210 static_cast<int>(Line)};
211}
212
214 const WorkListUnit &WU) {
215 llvm::TimeTraceScope tcs{timeTraceScopeName(Loc), [Loc, Pred]() {
216 return timeTraceMetadata(Pred, Loc);
217 }};
218 PrettyStackTraceStackFrame CrashInfo(Pred->getStackFrame());
219
220 // This work item is not necessarily related to the previous one, so
221 // the old current StackFrame and Block is no longer relevant.
222 // The new current StackFrame and Block should be set soon, but this
223 // guarantees that buggy access before that will trigger loud crashes instead
224 // of silently using stale data.
225 ExprEng.resetCurrStackFrameAndBlock();
226
227 // Dispatch on the location type.
228 switch (Loc.getKind()) {
230 HandleBlockEdge(Loc.castAs<BlockEdge>(), Pred);
231 break;
232
234 HandleBlockEntrance(Loc.castAs<BlockEntrance>(), Pred);
235 break;
236
238 assert(false && "BlockExit location never occur in forward analysis.");
239 break;
240
242 HandleCallEnter(Loc.castAs<CallEnter>(), Pred);
243 break;
244
246 ExprEng.processCallExit(Pred);
247 break;
248
250 assert(Pred->hasSinglePred() &&
251 "Assume epsilon has exactly one predecessor by construction");
252 ExplodedNode *PNode = Pred->getFirstPred();
253 dispatchWorkItem(Pred, PNode->getLocation(), WU);
254 break;
255 }
256 default:
257 assert(Loc.getAs<PostStmt>() ||
260 Loc.getAs<CallExitEnd>() ||
261 Loc.getAs<LoopExit>() ||
263 HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
264 break;
265 }
266}
267
268void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
269 const CFGBlock *Blk = L.getDst();
270 ExprEng.setCurrStackFrameAndBlock(Pred->getStackFrame(), Blk);
271
272 // Mark this block as visited.
273 const StackFrame *SF = Pred->getStackFrame();
274 FunctionSummaries->markVisitedBasicBlock(Blk->getBlockID(), SF->getDecl(),
275 SF->getCFG()->getNumBlockIDs());
276
277 // Display a prunable path note to the user if it's a virtual bases branch
278 // and we're taking the path that skips virtual base constructors.
280 L.getDst() == *L.getSrc()->succ_begin()) {
281 ProgramPoint P = L.withTag(getDataTags().make<NoteTag>(
282 [](BugReporterContext &, PathSensitiveBugReport &) -> std::string {
283 // TODO: Just call out the name of the most derived class
284 // when we know it.
285 return "Virtual base initialization skipped because "
286 "it has already been handled by the most derived class";
287 },
288 /*IsPrunable=*/true));
289 // Perform the transition.
290 Pred = makeNode(P, Pred->getState(), Pred);
291 if (!Pred)
292 return;
293 }
294
295 // Check if we are entering the EXIT block.
296 const CFGBlock &ExitBlk = L.getStackFrame()->getCFG()->getExit();
297 if (Blk == &ExitBlk) {
298 assert(ExitBlk.empty() && "EXIT block cannot contain Stmts.");
299
300 // Get return statement..
301 const ReturnStmt *RS = nullptr;
302 if (!L.getSrc()->empty()) {
303 CFGElement LastElement = L.getSrc()->back();
304 if (std::optional<CFGStmt> LastStmt = LastElement.getAs<CFGStmt>()) {
305 RS = dyn_cast<ReturnStmt>(LastStmt->getStmt());
306 } else if (std::optional<CFGAutomaticObjDtor> AutoDtor =
307 LastElement.getAs<CFGAutomaticObjDtor>()) {
308 RS = dyn_cast<ReturnStmt>(AutoDtor->getTriggerStmt());
309 }
310 }
311
312 ExplodedNodeSet CheckerNodes;
313 BlockEntrance BE(L.getSrc(), L.getDst(), Pred->getStackFrame());
314 ExprEng.runCheckersForBlockEntrance(BE, Pred, CheckerNodes);
315
316 // Process the final state transition.
317 for (ExplodedNode *P : CheckerNodes) {
318 ExprEng.processEndOfFunction(P, RS);
319 }
320
321 // This path is done. Don't enqueue any more nodes.
322 return;
323 }
324
325 // Call into the ExprEngine to process entering the CFGBlock.
326 BlockEntrance BE(L.getSrc(), L.getDst(), Pred->getStackFrame());
327 ExplodedNodeSet DstNodes;
328 NodeBuilder Builder(Pred, DstNodes, ExprEng.getBuilderContext());
329 ExprEng.processCFGBlockEntrance(L, BE, Builder, Pred);
330
331 // Auto-generate a node.
332 if (!Builder.hasGeneratedNodes()) {
333 Builder.generateNode(BE, Pred->State, Pred);
334 }
335
336 ExplodedNodeSet CheckerNodes;
337 for (auto *N : DstNodes) {
338 ExprEng.runCheckersForBlockEntrance(BE, N, CheckerNodes);
339 }
340
341 // Enqueue nodes onto the worklist.
342 enqueue(CheckerNodes);
343}
344
345void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
346 ExplodedNode *Pred) {
347 // Increment the block counter.
348 const StackFrame *SF = Pred->getStackFrame();
349 unsigned BlockId = L.getBlock()->getBlockID();
350 BlockCounter Counter = WList->getBlockCounter();
351 Counter = BCounterFactory.IncrementCount(Counter, SF, BlockId);
352 setBlockCounter(Counter);
353
354 // Process the entrance of the block.
355 if (std::optional<CFGElement> E = L.getFirstElement()) {
356 ExprEng.setCurrStackFrameAndBlock(Pred->getStackFrame(), L.getBlock());
357 ExprEng.processCFGElement(*E, Pred, 0);
358 } else
359 HandleBlockExit(L.getBlock(), Pred);
360}
361
362void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
363 if (const Stmt *Term = B->getTerminatorStmt()) {
364 ExprEng.setCurrStackFrameAndBlock(Pred->getStackFrame(), B);
365
366 switch (Term->getStmtClass()) {
367 default:
368 llvm_unreachable("Analysis for this terminator not implemented.");
369
370 case Stmt::CXXBindTemporaryExprClass:
371 HandleCleanupTemporaryBranch(
372 cast<CXXBindTemporaryExpr>(Term), B, Pred);
373 return;
374
375 // Model static initializers.
376 case Stmt::DeclStmtClass:
377 HandleStaticInit(cast<DeclStmt>(Term), B, Pred);
378 return;
379
380 case Stmt::BinaryOperatorClass: // '&&' and '||'
381 HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
382 return;
383
384 case Stmt::BinaryConditionalOperatorClass:
385 case Stmt::ConditionalOperatorClass:
386 HandleBranch(cast<AbstractConditionalOperator>(Term)->getCond(),
387 Term, B, Pred);
388 return;
389
390 // FIXME: Use constant-folding in CFG construction to simplify this
391 // case.
392
393 case Stmt::ChooseExprClass:
394 HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
395 return;
396
397 case Stmt::CXXTryStmtClass:
398 // Generate a node for each of the successors.
399 // Our logic for EH analysis can certainly be improved.
400 for (const CFGBlock *Succ : B->succs()) {
401 if (Succ) {
402 BlockEdge BE(B, Succ, Pred->getStackFrame());
403 if (ExplodedNode *N = makeNode(BE, Pred->State, Pred))
404 WList->enqueue(N);
405 }
406 }
407 return;
408
409 case Stmt::DoStmtClass:
410 HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
411 return;
412
413 case Stmt::CXXForRangeStmtClass:
414 HandleBranch(cast<CXXForRangeStmt>(Term)->getCond(), Term, B, Pred);
415 return;
416
417 case Stmt::ForStmtClass:
418 HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
419 return;
420
421 case Stmt::SEHLeaveStmtClass:
422 case Stmt::ContinueStmtClass:
423 case Stmt::BreakStmtClass:
424 case Stmt::GotoStmtClass:
425 break;
426
427 case Stmt::IfStmtClass:
428 HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
429 return;
430
431 case Stmt::IndirectGotoStmtClass: {
432 // Only 1 successor: the indirect goto dispatch block.
433 assert(B->succ_size() == 1);
434 ExplodedNodeSet Dst;
435 ExprEng.processIndirectGoto(Dst,
436 cast<IndirectGotoStmt>(Term)->getTarget(),
437 *(B->succ_begin()), Pred);
438 enqueue(Dst);
439 return;
440 }
441
442 case Stmt::ObjCForCollectionStmtClass:
443 // In the case of ObjCForCollectionStmt, it appears twice in a CFG:
444 //
445 // (1) inside a basic block, which represents the binding of the
446 // 'element' variable to a value.
447 // (2) in a terminator, which represents the branch.
448 //
449 // For (1), ExprEngine will bind a value (i.e., 0 or 1) indicating
450 // whether or not collection contains any more elements. We cannot
451 // just test to see if the element is nil because a container can
452 // contain nil elements.
453 HandleBranch(Term, Term, B, Pred);
454 return;
455
456 case Stmt::SwitchStmtClass: {
457 ExplodedNodeSet Dst;
458 ExprEng.processSwitch(cast<SwitchStmt>(Term), Pred, Dst);
459 // Enqueue the new frontier onto the worklist.
460 enqueue(Dst);
461 return;
462 }
463
464 case Stmt::WhileStmtClass:
465 HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
466 return;
467
468 case Stmt::GCCAsmStmtClass:
469 assert(cast<GCCAsmStmt>(Term)->isAsmGoto() && "Encountered GCCAsmStmt without labels");
470 // TODO: Handle jumping to labels
471 return;
472 }
473 }
474
476 HandleVirtualBaseBranch(B, Pred);
477 return;
478 }
479
480 assert(B->succ_size() == 1 &&
481 "Blocks with no terminator should have at most 1 successor.");
482
483 BlockEdge BE(B, *(B->succ_begin()), Pred->getStackFrame());
484 if (ExplodedNode *N = makeNode(BE, Pred->State, Pred))
485 WList->enqueue(N);
486}
487
488void CoreEngine::HandleCallEnter(const CallEnter &CE, ExplodedNode *Pred) {
489 ExprEng.setCurrStackFrameAndBlock(Pred->getStackFrame(), CE.getEntry());
490 ExprEng.processCallEnter(CE, Pred);
491}
492
493void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term,
494 const CFGBlock * B, ExplodedNode *Pred) {
495 assert(B->succ_size() == 2);
496 ExplodedNodeSet Dst;
497 ExprEng.processBranch(Cond, Pred, Dst, *(B->succ_begin()),
498 *(B->succ_begin() + 1),
499 getCompletedIterationCount(B, Pred));
500 // Enqueue the new frontier onto the worklist.
501 enqueue(Dst);
502}
503
504void CoreEngine::HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
505 const CFGBlock *B,
506 ExplodedNode *Pred) {
507 assert(B->succ_size() == 2);
508 ExplodedNodeSet Dst;
509 ExprEng.processCleanupTemporaryBranch(BTE, Pred, Dst, *(B->succ_begin()),
510 *(B->succ_begin() + 1));
511 // Enqueue the new frontier onto the worklist.
512 enqueue(Dst);
513}
514
515void CoreEngine::HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
516 ExplodedNode *Pred) {
517 assert(B->succ_size() == 2);
518 ExplodedNodeSet Dst;
519 ExprEng.processStaticInitializer(DS, Pred, Dst, *(B->succ_begin()),
520 *(B->succ_begin() + 1));
521 // Enqueue the new frontier onto the worklist.
522 enqueue(Dst);
523}
524
525void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
526 ExplodedNode *Pred) {
527 assert(B);
528 assert(!B->empty());
529
530 // We no-op by skipping any FullExprCleanup
531 while (StmtIdx < B->size() &&
532 (*B)[StmtIdx].getKind() == CFGElement::FullExprCleanup) {
533 StmtIdx++;
534 }
535
536 if (StmtIdx == B->size())
537 HandleBlockExit(B, Pred);
538 else {
539 ExprEng.setCurrStackFrameAndBlock(Pred->getStackFrame(), B);
540 ExprEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx);
541 }
542}
543
544void CoreEngine::HandleVirtualBaseBranch(const CFGBlock *B,
545 ExplodedNode *Pred) {
546 const StackFrame *SF = Pred->getStackFrame();
547 if (const auto *CallerCtor =
548 dyn_cast_or_null<CXXConstructExpr>(SF->getCallSite())) {
549 switch (CallerCtor->getConstructionKind()) {
552 BlockEdge Loc(B, *B->succ_begin(), SF);
553 HandleBlockEdge(Loc, Pred);
554 return;
555 }
556 default:
557 break;
558 }
559 }
560
561 // We either don't see a parent stack frame because we're in the top frame,
562 // or the parent stack frame doesn't initialize our virtual bases.
563 BlockEdge Loc(B, *(B->succ_begin() + 1), SF);
564 HandleBlockEdge(Loc, Pred);
565}
566
568 ProgramStateRef State, ExplodedNode *Pred,
569 bool MarkAsSink) const {
570 MarkAsSink = MarkAsSink || State->isPosteriorlyOverconstrained();
571
572 bool IsNew;
573 ExplodedNode *N = G.getNode(Loc, State, MarkAsSink, &IsNew);
574 N->addPredecessor(Pred, G);
575
576 return IsNew ? N : nullptr;
577}
578
580 const CFGBlock *Block, unsigned Idx) {
581 assert(Block);
582 assert(!N->isSink());
583
584 // Check if this node entered a callee.
585 if (N->getLocation().getAs<CallEnter>()) {
586 // Still use the index of the CallExpr. It's needed to create the callee
587 // StackFrame.
588 WList->enqueue(N, Block, Idx);
589 return;
590 }
591
592 // Do not create extra nodes. Move to the next CFG element.
593 if (N->getLocation().getAs<PostInitializer>() ||
595 N->getLocation().getAs<LoopExit>()) {
596 WList->enqueue(N, Block, Idx+1);
597 return;
598 }
599
600 if (N->getLocation().getAs<EpsilonPoint>()) {
601 WList->enqueue(N, Block, Idx);
602 return;
603 }
604
605 if ((*Block)[Idx].getKind() == CFGElement::NewAllocator) {
606 WList->enqueue(N, Block, Idx+1);
607 return;
608 }
609
610 // At this point, we know we're processing a normal statement.
611 CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>();
612 PostStmt Loc(CS.getStmt(), N->getStackFrame());
613
614 if (Loc == N->getLocation().withTag(nullptr)) {
615 // Note: 'N' should be a fresh node because otherwise it shouldn't be
616 // a member of Deferred.
617 WList->enqueue(N, Block, Idx+1);
618 return;
619 }
620
621 ExplodedNode *Succ = makeNode(Loc, N->getState(), N);
622
623 if (Succ)
624 WList->enqueue(Succ, Block, Idx+1);
625}
626
627std::optional<unsigned>
628CoreEngine::getCompletedIterationCount(const CFGBlock *B,
629 ExplodedNode *Pred) const {
630 const StackFrame *SF = Pred->getStackFrame();
631 BlockCounter Counter = WList->getBlockCounter();
632 unsigned BlockCount = Counter.getNumVisited(SF, B->getBlockID());
633
634 const Stmt *Term = B->getTerminatorStmt();
636 assert(BlockCount >= 1 &&
637 "Block count of currently analyzed block must be >= 1");
638 return BlockCount - 1;
639 }
640 if (isa<DoStmt>(Term)) {
641 // In a do-while loop one iteration happens before the first evaluation of
642 // the loop condition, so we don't subtract one.
643 return BlockCount;
644 }
645 // ObjCForCollectionStmt is skipped intentionally because the current
646 // application of the iteration counts is not relevant for it.
647 return std::nullopt;
648}
649
651 for (const auto I : Set)
652 WList->enqueue(I);
653}
654
656 unsigned Idx) {
657 for (const auto I : Set)
658 enqueueStmtNode(I, Block, Idx);
659}
660
662 for (ExplodedNode *Node : Set) {
663 const StackFrame *SF = Node->getStackFrame();
664
665 // If we are in an inlined call, generate CallExitBegin node.
666 if (SF->getParent()) {
667 // Use the callee stack frame.
668 CallExitBegin Loc(SF, RS);
669 if (ExplodedNode *Succ = makeNode(Loc, Node->getState(), Node))
670 WList->enqueue(Succ);
671 } else {
672 // TODO: We should run remove dead bindings here.
673 G.addEndOfPath(Node);
674 NumPathsExplored++;
675 }
676 }
677}
678
680 ProgramStateRef State,
681 ExplodedNode *FromN, bool MarkAsSink) {
682 HasGeneratedNodes = true;
683 Frontier.erase(FromN);
684 ExplodedNode *N = C.getEngine().makeNode(Loc, State, FromN, MarkAsSink);
685
686 Frontier.insert(N);
687
688 return N;
689}
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static std::unique_ptr< WorkList > generateWorkList(AnalyzerOptions &Opts)
ALWAYS_ENABLED_STATISTIC(NumReachedMaxSteps, "The # of times we reached the max number of steps.")
static std::string timeTraceScopeName(const ProgramPoint &Loc)
static llvm::TimeTraceMetadata timeTraceMetadata(const ExplodedNode *Pred, const ProgramPoint &Loc)
static Decl::Kind getKind(const Decl *D)
#define STAT_COUNTER(VARNAME, DESC)
Defines the clang::Expr interface and subclasses for C++ expressions.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
#define SM(sm)
SourceManager & getSourceManager()
Definition ASTContext.h:865
ASTContext & getASTContext() const
Stores options for the analyzer from the command line.
ExplorationStrategyKind getExplorationStrategy() const
const CFGBlock * getSrc() const
const CFGBlock * getDst() const
std::optional< CFGElement > getFirstElement() const
const CFGBlock * getBlock() const
Represents a single basic block in a source-level CFG.
Definition CFG.h:639
CFGElement back() const
Definition CFG.h:942
unsigned size() const
Definition CFG.h:986
succ_range succs()
Definition CFG.h:1034
bool empty() const
Definition CFG.h:987
CFGTerminator getTerminator() const
Definition CFG.h:1119
succ_iterator succ_begin()
Definition CFG.h:1024
Stmt * getTerminatorStmt()
Definition CFG.h:1121
unsigned getBlockID() const
Definition CFG.h:1141
unsigned succ_size() const
Definition CFG.h:1042
Represents a top-level expression in a basic block.
Definition CFG.h:55
@ FullExprCleanup
Definition CFG.h:65
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type.
Definition CFG.h:100
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
Definition CFG.h:110
const Stmt * getStmt() const
Definition CFG.h:140
bool isVirtualBaseBranch() const
Definition CFG.h:608
CFGBlock & getExit()
Definition CFG.h:1374
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Definition CFG.h:1451
Represents a point when we begin processing an inlined call.
const CFGBlock * getEntry() const
Returns the entry block in the CFG for the entered function.
Represents a point when we start the call exit sequence (for inlined call).
Represents a point when we finish the call exit sequence (for inlined call).
This is a meta program point, which should be skipped by all the diagnostic reasoning etc.
Represents a point when we exit a loop.
Represents a program point just after an implicit call event.
static StringRef getProgramPointKindName(Kind K)
ProgramPoint withTag(const ProgramPointTag *tag) const
Create a new ProgramPoint object that is the same as the original except for using the specified tag ...
const StackFrame * getStackFrame() const
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3170
It represents a stack frame of the call stack.
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
const Expr * getCallSite() const
const Decl * getDecl() const
const StackFrame * getParent() const
It might return null.
Stmt - This represents one statement.
Definition Stmt.h:86
An abstract data type used to count the number of times a given block has been visited along a path a...
unsigned getNumVisited(const StackFrame *CallSite, unsigned BlockID) const
CoreEngine(ExprEngine &exprengine, FunctionSummariesTy *FS, AnalyzerOptions &Opts)
Construct a CoreEngine object to analyze the provided CFG.
DataTag::Factory & getDataTags()
Definition CoreEngine.h:211
friend class ExprEngine
Definition CoreEngine.h:51
void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx)
Enqueue a single node created as a result of statement processing.
void dispatchWorkItem(ExplodedNode *Pred, ProgramPoint Loc, const WorkListUnit &WU)
Dispatch the work list item based on the given location information.
friend class NodeBuilder
Definition CoreEngine.h:52
void enqueueStmtNodes(ExplodedNodeSet &Set, const CFGBlock *Block, unsigned Idx)
Enqueue nodes that were created as a result of processing a statement onto the work list.
bool ExecuteWorkList(const StackFrame *SF, unsigned Steps, ProgramStateRef InitState)
ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
void enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS)
enqueue the nodes corresponding to the end of function onto the end of path / work list.
ExplodedNode * makeNode(const ProgramPoint &Loc, ProgramStateRef State, ExplodedNode *Pred, bool MarkAsSink=false) const
void enqueue(ExplodedNodeSet &Set)
Enqueue the given set of nodes onto the work list.
ExplodedNodeSet is a set of ExplodedNode * elements with the invariant that its elements cannot be nu...
const ProgramStateRef & getState() const
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
void addPredecessor(ExplodedNode *V, ExplodedGraph &G)
addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...
ExplodedNode * getFirstPred()
const StackFrame * getStackFrame() const
void setCurrStackFrameAndBlock(const StackFrame *SF, const CFGBlock *B)
Definition ExprEngine.h:244
void markVisitedBasicBlock(unsigned ID, const Decl *D, unsigned TotalIDs)
const NodeBuilderContext & C
Definition CoreEngine.h:267
ExplodedNode * generateNode(const ProgramPoint &PP, ProgramStateRef State, ExplodedNode *Pred, bool MarkAsSink=false)
Generates a node in the ExplodedGraph.
ExplodedNodeSet & Frontier
The frontier set - a set of nodes which need to be propagated after the builder dies.
Definition CoreEngine.h:273
While alive, includes the current analysis stack in a crash trace.
SValKind getKind() const
Definition SVals.h:91
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
Definition SVals.h:87
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Definition SVals.h:83
ExplodedNode * getNode() const
Returns the node associated with the worklist unit.
Definition WorkList.h:48
unsigned getIndex() const
Return the index within the CFGBlock for the worklist unit.
Definition WorkList.h:57
const CFGBlock * getBlock() const
Returns the CFGblock associated with the worklist unit.
Definition WorkList.h:54
BlockCounter getBlockCounter() const
Returns the block counter map associated with the worklist unit.
Definition WorkList.h:51
static std::unique_ptr< WorkList > makeUnexploredFirstPriorityLocationQueue()
Definition WorkList.cpp:297
static std::unique_ptr< WorkList > makeUnexploredFirstPriorityQueue()
Definition WorkList.cpp:243
static std::unique_ptr< WorkList > makeBFSBlockDFSContents()
Definition WorkList.cpp:126
static std::unique_ptr< WorkList > makeBFS()
Definition WorkList.cpp:85
static std::unique_ptr< WorkList > makeDFS()
Definition WorkList.cpp:81
static std::unique_ptr< WorkList > makeUnexploredFirst()
Definition WorkList.cpp:187
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
Expr * Cond
};
U cast(CodeGen::Address addr)
Definition Address.h:327