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 LocationContext *L, 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 = &(L->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(),
101 L->getDecl(),
102 L->getCFG()->getNumBlockIDs());
103
104 // Get the solitary successor.
105 const CFGBlock *Succ = *(Entry->succ_begin());
106
107 // Construct an edge representing the
108 // starting location in the function.
109 BlockEdge StartLoc(Entry, Succ, L);
110
111 // Set the current block counter to being empty.
112 setBlockCounter(BCounterFactory.GetEmptyCounter());
113
114 if (!InitState)
115 InitState = ExprEng.getInitialState(L);
116
117 bool IsNew;
118 ExplodedNode *Node = G.getNode(StartLoc, InitState, false, &IsNew);
119 assert(IsNew);
120 G.designateAsRoot(Node);
121
122 ExprEng.setCurrLocationContextAndBlock(Node->getLocationContext(), Succ);
123
124 ExplodedNodeSet DstBegin;
125 ExprEng.processBeginOfFunction(Node, DstBegin, StartLoc);
126
127 enqueue(DstBegin);
128 }
129
130 // Check if we have a steps limit
131 bool UnlimitedSteps = MaxSteps == 0;
132
133 // Cap our pre-reservation in the event that the user specifies
134 // a very large number of maximum steps.
135 const unsigned PreReservationCap = 4000000;
136 if(!UnlimitedSteps)
137 G.reserve(std::min(MaxSteps, PreReservationCap));
138
139 auto ProcessWList = [this, UnlimitedSteps](unsigned MaxSteps) {
140 unsigned Steps = MaxSteps;
141 while (WList->hasWork()) {
142 if (!UnlimitedSteps) {
143 if (Steps == 0) {
144 NumReachedMaxSteps++;
145 break;
146 }
147 --Steps;
148 }
149
150 NumSteps++;
151
152 const WorkListUnit &WU = WList->dequeue();
153
154 // Set the current block counter.
155 setBlockCounter(WU.getBlockCounter());
156
157 // Retrieve the node.
158 ExplodedNode *Node = WU.getNode();
159
160 dispatchWorkItem(Node, Node->getLocation(), WU);
161 }
162 return MaxSteps - Steps;
163 };
164 const unsigned STUSteps = ProcessWList(MaxSteps);
165
166 if (CTUWList) {
167 NumSTUSteps += STUSteps;
168 const unsigned MinCTUSteps =
169 this->ExprEng.getAnalysisManager().options.CTUMaxNodesMin;
170 const unsigned Pct =
171 this->ExprEng.getAnalysisManager().options.CTUMaxNodesPercentage;
172 unsigned MaxCTUSteps = std::max(STUSteps * Pct / 100, MinCTUSteps);
173
174 WList = std::move(CTUWList);
175 const unsigned CTUSteps = ProcessWList(MaxCTUSteps);
176 NumCTUSteps += CTUSteps;
177 }
178
179 ExprEng.processEndWorklist();
180 return WList->hasWork();
181}
182
183static std::string timeTraceScopeName(const ProgramPoint &Loc) {
184 if (llvm::timeTraceProfilerEnabled()) {
185 return llvm::formatv("dispatchWorkItem {0}",
187 .str();
188 }
189 return "";
190}
191
192static llvm::TimeTraceMetadata timeTraceMetadata(const ExplodedNode *Pred,
193 const ProgramPoint &Loc) {
194 // If time-trace profiler is not enabled, this function is never called.
195 assert(llvm::timeTraceProfilerEnabled());
196 std::string Detail = "";
197 if (const auto SP = Loc.getAs<StmtPoint>()) {
198 if (const Stmt *S = SP->getStmt())
199 Detail = S->getStmtClassName();
200 }
201 auto SLoc = Loc.getSourceLocation();
202 if (!SLoc)
203 return llvm::TimeTraceMetadata{std::move(Detail), ""};
204 const auto &SM = Pred->getLocationContext()
206 ->getASTContext()
208 auto Line = SM.getPresumedLineNumber(*SLoc);
209 auto Fname = SM.getFilename(*SLoc);
210 return llvm::TimeTraceMetadata{std::move(Detail), Fname.str(),
211 static_cast<int>(Line)};
212}
213
215 const WorkListUnit &WU) {
216 llvm::TimeTraceScope tcs{timeTraceScopeName(Loc), [Loc, Pred]() {
217 return timeTraceMetadata(Pred, Loc);
218 }};
220
221 // This work item is not necessarily related to the previous one, so
222 // the old current LocationContext and Block is no longer relevant.
223 // The new current LocationContext and Block should be set soon, but this
224 // guarantees that buggy access before that will trigger loud crashes instead
225 // of silently using stale data.
226 ExprEng.resetCurrLocationContextAndBlock();
227
228 // Dispatch on the location type.
229 switch (Loc.getKind()) {
231 HandleBlockEdge(Loc.castAs<BlockEdge>(), Pred);
232 break;
233
235 HandleBlockEntrance(Loc.castAs<BlockEntrance>(), Pred);
236 break;
237
239 assert(false && "BlockExit location never occur in forward analysis.");
240 break;
241
243 HandleCallEnter(Loc.castAs<CallEnter>(), Pred);
244 break;
245
247 ExprEng.processCallExit(Pred);
248 break;
249
251 assert(Pred->hasSinglePred() &&
252 "Assume epsilon has exactly one predecessor by construction");
253 ExplodedNode *PNode = Pred->getFirstPred();
254 dispatchWorkItem(Pred, PNode->getLocation(), WU);
255 break;
256 }
257 default:
258 assert(Loc.getAs<PostStmt>() ||
261 Loc.getAs<CallExitEnd>() ||
262 Loc.getAs<LoopExit>() ||
264 HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
265 break;
266 }
267}
268
269void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
270 const CFGBlock *Blk = L.getDst();
272
273 // Mark this block as visited.
274 const LocationContext *LC = Pred->getLocationContext();
275 FunctionSummaries->markVisitedBasicBlock(Blk->getBlockID(),
276 LC->getDecl(),
277 LC->getCFG()->getNumBlockIDs());
278
279 // Display a prunable path note to the user if it's a virtual bases branch
280 // and we're taking the path that skips virtual base constructors.
282 L.getDst() == *L.getSrc()->succ_begin()) {
283 ProgramPoint P = L.withTag(getDataTags().make<NoteTag>(
284 [](BugReporterContext &, PathSensitiveBugReport &) -> std::string {
285 // TODO: Just call out the name of the most derived class
286 // when we know it.
287 return "Virtual base initialization skipped because "
288 "it has already been handled by the most derived class";
289 },
290 /*IsPrunable=*/true));
291 // Perform the transition.
292 Pred = makeNode(P, Pred->getState(), Pred);
293 if (!Pred)
294 return;
295 }
296
297 // Check if we are entering the EXIT block.
298 const CFGBlock &ExitBlk = L.getLocationContext()->getCFG()->getExit();
299 if (Blk == &ExitBlk) {
300 assert(ExitBlk.empty() && "EXIT block cannot contain Stmts.");
301
302 // Get return statement..
303 const ReturnStmt *RS = nullptr;
304 if (!L.getSrc()->empty()) {
305 CFGElement LastElement = L.getSrc()->back();
306 if (std::optional<CFGStmt> LastStmt = LastElement.getAs<CFGStmt>()) {
307 RS = dyn_cast<ReturnStmt>(LastStmt->getStmt());
308 } else if (std::optional<CFGAutomaticObjDtor> AutoDtor =
309 LastElement.getAs<CFGAutomaticObjDtor>()) {
310 RS = dyn_cast<ReturnStmt>(AutoDtor->getTriggerStmt());
311 }
312 }
313
314 ExplodedNodeSet CheckerNodes;
315 BlockEntrance BE(L.getSrc(), L.getDst(), Pred->getLocationContext());
316 ExprEng.runCheckersForBlockEntrance(BE, Pred, CheckerNodes);
317
318 // Process the final state transition.
319 for (ExplodedNode *P : CheckerNodes) {
320 ExprEng.processEndOfFunction(P, RS);
321 }
322
323 // This path is done. Don't enqueue any more nodes.
324 return;
325 }
326
327 // Call into the ExprEngine to process entering the CFGBlock.
328 BlockEntrance BE(L.getSrc(), L.getDst(), Pred->getLocationContext());
329 ExplodedNodeSet DstNodes;
330 NodeBuilder Builder(Pred, DstNodes, ExprEng.getBuilderContext());
331 ExprEng.processCFGBlockEntrance(L, BE, Builder, Pred);
332
333 // Auto-generate a node.
334 if (!Builder.hasGeneratedNodes()) {
335 Builder.generateNode(BE, Pred->State, Pred);
336 }
337
338 ExplodedNodeSet CheckerNodes;
339 for (auto *N : DstNodes) {
340 ExprEng.runCheckersForBlockEntrance(BE, N, CheckerNodes);
341 }
342
343 // Enqueue nodes onto the worklist.
344 enqueue(CheckerNodes);
345}
346
347void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
348 ExplodedNode *Pred) {
349 // Increment the block counter.
350 const LocationContext *LC = Pred->getLocationContext();
351 unsigned BlockId = L.getBlock()->getBlockID();
352 BlockCounter Counter = WList->getBlockCounter();
353 Counter = BCounterFactory.IncrementCount(Counter, LC->getStackFrame(),
354 BlockId);
355 setBlockCounter(Counter);
356
357 // Process the entrance of the block.
358 if (std::optional<CFGElement> E = L.getFirstElement()) {
359 ExprEng.setCurrLocationContextAndBlock(Pred->getLocationContext(),
360 L.getBlock());
361 ExprEng.processCFGElement(*E, Pred, 0);
362 } else
363 HandleBlockExit(L.getBlock(), Pred);
364}
365
366void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
367 if (const Stmt *Term = B->getTerminatorStmt()) {
368 ExprEng.setCurrLocationContextAndBlock(Pred->getLocationContext(), B);
369
370 switch (Term->getStmtClass()) {
371 default:
372 llvm_unreachable("Analysis for this terminator not implemented.");
373
374 case Stmt::CXXBindTemporaryExprClass:
375 HandleCleanupTemporaryBranch(
376 cast<CXXBindTemporaryExpr>(Term), B, Pred);
377 return;
378
379 // Model static initializers.
380 case Stmt::DeclStmtClass:
381 HandleStaticInit(cast<DeclStmt>(Term), B, Pred);
382 return;
383
384 case Stmt::BinaryOperatorClass: // '&&' and '||'
385 HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
386 return;
387
388 case Stmt::BinaryConditionalOperatorClass:
389 case Stmt::ConditionalOperatorClass:
390 HandleBranch(cast<AbstractConditionalOperator>(Term)->getCond(),
391 Term, B, Pred);
392 return;
393
394 // FIXME: Use constant-folding in CFG construction to simplify this
395 // case.
396
397 case Stmt::ChooseExprClass:
398 HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
399 return;
400
401 case Stmt::CXXTryStmtClass:
402 // Generate a node for each of the successors.
403 // Our logic for EH analysis can certainly be improved.
404 for (const CFGBlock *Succ : B->succs()) {
405 if (Succ) {
406 BlockEdge BE(B, Succ, Pred->getLocationContext());
407 if (ExplodedNode *N = makeNode(BE, Pred->State, Pred))
408 WList->enqueue(N);
409 }
410 }
411 return;
412
413 case Stmt::DoStmtClass:
414 HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
415 return;
416
417 case Stmt::CXXForRangeStmtClass:
418 HandleBranch(cast<CXXForRangeStmt>(Term)->getCond(), Term, B, Pred);
419 return;
420
421 case Stmt::ForStmtClass:
422 HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
423 return;
424
425 case Stmt::SEHLeaveStmtClass:
426 case Stmt::ContinueStmtClass:
427 case Stmt::BreakStmtClass:
428 case Stmt::GotoStmtClass:
429 break;
430
431 case Stmt::IfStmtClass:
432 HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
433 return;
434
435 case Stmt::IndirectGotoStmtClass: {
436 // Only 1 successor: the indirect goto dispatch block.
437 assert(B->succ_size() == 1);
438 ExplodedNodeSet Dst;
439 ExprEng.processIndirectGoto(Dst,
440 cast<IndirectGotoStmt>(Term)->getTarget(),
441 *(B->succ_begin()), Pred);
442 enqueue(Dst);
443 return;
444 }
445
446 case Stmt::ObjCForCollectionStmtClass:
447 // In the case of ObjCForCollectionStmt, it appears twice in a CFG:
448 //
449 // (1) inside a basic block, which represents the binding of the
450 // 'element' variable to a value.
451 // (2) in a terminator, which represents the branch.
452 //
453 // For (1), ExprEngine will bind a value (i.e., 0 or 1) indicating
454 // whether or not collection contains any more elements. We cannot
455 // just test to see if the element is nil because a container can
456 // contain nil elements.
457 HandleBranch(Term, Term, B, Pred);
458 return;
459
460 case Stmt::SwitchStmtClass: {
461 ExplodedNodeSet Dst;
462 ExprEng.processSwitch(cast<SwitchStmt>(Term), Pred, Dst);
463 // Enqueue the new frontier onto the worklist.
464 enqueue(Dst);
465 return;
466 }
467
468 case Stmt::WhileStmtClass:
469 HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
470 return;
471
472 case Stmt::GCCAsmStmtClass:
473 assert(cast<GCCAsmStmt>(Term)->isAsmGoto() && "Encountered GCCAsmStmt without labels");
474 // TODO: Handle jumping to labels
475 return;
476 }
477 }
478
480 HandleVirtualBaseBranch(B, Pred);
481 return;
482 }
483
484 assert(B->succ_size() == 1 &&
485 "Blocks with no terminator should have at most 1 successor.");
486
487 BlockEdge BE(B, *(B->succ_begin()), Pred->getLocationContext());
488 if (ExplodedNode *N = makeNode(BE, Pred->State, Pred))
489 WList->enqueue(N);
490}
491
492void CoreEngine::HandleCallEnter(const CallEnter &CE, ExplodedNode *Pred) {
493 ExprEng.setCurrLocationContextAndBlock(Pred->getLocationContext(),
494 CE.getEntry());
495 ExprEng.processCallEnter(CE, Pred);
496}
497
498void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term,
499 const CFGBlock * B, ExplodedNode *Pred) {
500 assert(B->succ_size() == 2);
501 ExplodedNodeSet Dst;
502 ExprEng.processBranch(Cond, Pred, Dst, *(B->succ_begin()),
503 *(B->succ_begin() + 1),
504 getCompletedIterationCount(B, Pred));
505 // Enqueue the new frontier onto the worklist.
506 enqueue(Dst);
507}
508
509void CoreEngine::HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
510 const CFGBlock *B,
511 ExplodedNode *Pred) {
512 assert(B->succ_size() == 2);
513 ExplodedNodeSet Dst;
514 ExprEng.processCleanupTemporaryBranch(BTE, Pred, Dst, *(B->succ_begin()),
515 *(B->succ_begin() + 1));
516 // Enqueue the new frontier onto the worklist.
517 enqueue(Dst);
518}
519
520void CoreEngine::HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
521 ExplodedNode *Pred) {
522 assert(B->succ_size() == 2);
523 ExplodedNodeSet Dst;
524 ExprEng.processStaticInitializer(DS, Pred, Dst, *(B->succ_begin()),
525 *(B->succ_begin() + 1));
526 // Enqueue the new frontier onto the worklist.
527 enqueue(Dst);
528}
529
530void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
531 ExplodedNode *Pred) {
532 assert(B);
533 assert(!B->empty());
534
535 // We no-op by skipping any FullExprCleanup
536 while (StmtIdx < B->size() &&
537 (*B)[StmtIdx].getKind() == CFGElement::FullExprCleanup) {
538 StmtIdx++;
539 }
540
541 if (StmtIdx == B->size())
542 HandleBlockExit(B, Pred);
543 else {
544 ExprEng.setCurrLocationContextAndBlock(Pred->getLocationContext(), B);
545 ExprEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx);
546 }
547}
548
549void CoreEngine::HandleVirtualBaseBranch(const CFGBlock *B,
550 ExplodedNode *Pred) {
551 const LocationContext *LCtx = Pred->getLocationContext();
552 if (const auto *CallerCtor = dyn_cast_or_null<CXXConstructExpr>(
553 LCtx->getStackFrame()->getCallSite())) {
554 switch (CallerCtor->getConstructionKind()) {
557 BlockEdge Loc(B, *B->succ_begin(), LCtx);
558 HandleBlockEdge(Loc, Pred);
559 return;
560 }
561 default:
562 break;
563 }
564 }
565
566 // We either don't see a parent stack frame because we're in the top frame,
567 // or the parent stack frame doesn't initialize our virtual bases.
568 BlockEdge Loc(B, *(B->succ_begin() + 1), LCtx);
569 HandleBlockEdge(Loc, Pred);
570}
571
573 ProgramStateRef State, ExplodedNode *Pred,
574 bool MarkAsSink) const {
575 MarkAsSink = MarkAsSink || State->isPosteriorlyOverconstrained();
576
577 bool IsNew;
578 ExplodedNode *N = G.getNode(Loc, State, MarkAsSink, &IsNew);
579 N->addPredecessor(Pred, G);
580
581 return IsNew ? N : nullptr;
582}
583
585 const CFGBlock *Block, unsigned Idx) {
586 assert(Block);
587 assert(!N->isSink());
588
589 // Check if this node entered a callee.
590 if (N->getLocation().getAs<CallEnter>()) {
591 // Still use the index of the CallExpr. It's needed to create the callee
592 // StackFrameContext.
593 WList->enqueue(N, Block, Idx);
594 return;
595 }
596
597 // Do not create extra nodes. Move to the next CFG element.
598 if (N->getLocation().getAs<PostInitializer>() ||
600 N->getLocation().getAs<LoopExit>()) {
601 WList->enqueue(N, Block, Idx+1);
602 return;
603 }
604
605 if (N->getLocation().getAs<EpsilonPoint>()) {
606 WList->enqueue(N, Block, Idx);
607 return;
608 }
609
610 if ((*Block)[Idx].getKind() == CFGElement::NewAllocator) {
611 WList->enqueue(N, Block, Idx+1);
612 return;
613 }
614
615 // At this point, we know we're processing a normal statement.
616 CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>();
618
619 if (Loc == N->getLocation().withTag(nullptr)) {
620 // Note: 'N' should be a fresh node because otherwise it shouldn't be
621 // a member of Deferred.
622 WList->enqueue(N, Block, Idx+1);
623 return;
624 }
625
626 ExplodedNode *Succ = makeNode(Loc, N->getState(), N);
627
628 if (Succ)
629 WList->enqueue(Succ, Block, Idx+1);
630}
631
632std::optional<unsigned>
633CoreEngine::getCompletedIterationCount(const CFGBlock *B,
634 ExplodedNode *Pred) const {
635 const LocationContext *LC = Pred->getLocationContext();
636 BlockCounter Counter = WList->getBlockCounter();
637 unsigned BlockCount =
638 Counter.getNumVisited(LC->getStackFrame(), B->getBlockID());
639
640 const Stmt *Term = B->getTerminatorStmt();
642 assert(BlockCount >= 1 &&
643 "Block count of currently analyzed block must be >= 1");
644 return BlockCount - 1;
645 }
646 if (isa<DoStmt>(Term)) {
647 // In a do-while loop one iteration happens before the first evaluation of
648 // the loop condition, so we don't subtract one.
649 return BlockCount;
650 }
651 // ObjCForCollectionStmt is skipped intentionally because the current
652 // application of the iteration counts is not relevant for it.
653 return std::nullopt;
654}
655
657 for (const auto I : Set)
658 WList->enqueue(I);
659}
660
662 unsigned Idx) {
663 for (const auto I : Set)
664 enqueueStmtNode(I, Block, Idx);
665}
666
668 for (ExplodedNode *Node : Set) {
669 const LocationContext *LocCtx = Node->getLocationContext();
670
671 // If we are in an inlined call, generate CallExitBegin node.
672 if (LocCtx->getParent()) {
673 // Use the callee location context.
675 if (ExplodedNode *Succ = makeNode(Loc, Node->getState(), Node))
676 WList->enqueue(Succ);
677 } else {
678 // TODO: We should run remove dead bindings here.
679 G.addEndOfPath(Node);
680 NumPathsExplored++;
681 }
682 }
683}
684
686 ProgramStateRef State,
687 ExplodedNode *FromN, bool MarkAsSink) {
688 HasGeneratedNodes = true;
689 Frontier.erase(FromN);
690 ExplodedNode *N = C.getEngine().makeNode(Loc, State, FromN, MarkAsSink);
691
692 Frontier.insert(N);
693
694 return N;
695}
696
698 bool Branch,
699 ExplodedNode *NodePred) {
700 const CFGBlock *Dst = Branch ? DstT : DstF;
701
702 if (!Dst)
703 return nullptr;
704
706 BlockEdge(C.getBlock(), Dst, NodePred->getLocationContext());
707 ExplodedNode *Succ = NodeBuilder::generateNode(Loc, State, NodePred);
708 return Succ;
709}
710
713 ExplodedNode *Pred) {
714 BlockEdge BE(C.getBlock(), Block, Pred->getLocationContext());
715 return generateNode(BE, St, Pred);
716}
717
719 ExplodedNode *Pred) {
720 // Get the block for the default case.
721 const CFGBlock *Src = C.getBlock();
722 assert(Src->succ_rbegin() != Src->succ_rend());
723 CFGBlock *DefaultBlock = *Src->succ_rbegin();
724
725 // Basic correctness check for default blocks that are unreachable and not
726 // caught by earlier stages.
727 if (!DefaultBlock)
728 return nullptr;
729
730 BlockEdge BE(Src, DefaultBlock, Pred->getLocationContext());
731 return generateNode(BE, St, Pred);
732}
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:859
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:632
CFGElement back() const
Definition CFG.h:935
succ_reverse_iterator succ_rend()
Definition CFG.h:1023
unsigned size() const
Definition CFG.h:979
succ_reverse_iterator succ_rbegin()
Definition CFG.h:1022
succ_range succs()
Definition CFG.h:1027
bool empty() const
Definition CFG.h:980
CFGTerminator getTerminator() const
Definition CFG.h:1112
succ_iterator succ_begin()
Definition CFG.h:1017
Stmt * getTerminatorStmt()
Definition CFG.h:1114
unsigned getBlockID() const
Definition CFG.h:1134
unsigned succ_size() const
Definition CFG.h:1035
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:601
CFGBlock & getExit()
Definition CFG.h:1366
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Definition CFG.h:1443
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.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
const Decl * getDecl() const
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
const LocationContext * getParent() const
It might return null.
const StackFrameContext * getStackFrame() const
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 ...
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
const LocationContext * getLocationContext() const
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3152
const Stmt * getCallSite() const
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 StackFrameContext *CallSite, unsigned BlockID) const
ExplodedNode * generateNode(ProgramStateRef State, bool branch, ExplodedNode *Pred)
CoreEngine(ExprEngine &exprengine, FunctionSummariesTy *FS, AnalyzerOptions &Opts)
Construct a CoreEngine object to analyze the provided CFG.
DataTag::Factory & getDataTags()
Definition CoreEngine.h:189
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 LocationContext *L, 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 ...
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
void setCurrLocationContextAndBlock(const LocationContext *LC, const CFGBlock *B)
Definition ExprEngine.h:246
void markVisitedBasicBlock(unsigned ID, const Decl *D, unsigned TotalIDs)
const NodeBuilderContext & C
Definition CoreEngine.h:247
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:253
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 * generateCaseStmtNode(const CFGBlock *Block, ProgramStateRef State, ExplodedNode *Pred)
ExplodedNode * generateDefaultCaseNode(ProgramStateRef State, ExplodedNode *Pred)
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:299
static std::unique_ptr< WorkList > makeUnexploredFirstPriorityQueue()
Definition WorkList.cpp:245
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:188
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