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 NodeBuilderContext BuilderCtx(*this, StartLoc.getDst(), Node);
123 ExplodedNodeSet DstBegin;
124 ExprEng.processBeginOfFunction(BuilderCtx, 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->getLocationContext()
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 }};
219 // Dispatch on the location type.
220 switch (Loc.getKind()) {
222 HandleBlockEdge(Loc.castAs<BlockEdge>(), Pred);
223 break;
224
226 HandleBlockEntrance(Loc.castAs<BlockEntrance>(), Pred);
227 break;
228
230 assert(false && "BlockExit location never occur in forward analysis.");
231 break;
232
234 HandleCallEnter(Loc.castAs<CallEnter>(), Pred);
235 break;
236
238 ExprEng.processCallExit(Pred);
239 break;
240
242 assert(Pred->hasSinglePred() &&
243 "Assume epsilon has exactly one predecessor by construction");
244 ExplodedNode *PNode = Pred->getFirstPred();
245 dispatchWorkItem(Pred, PNode->getLocation(), WU);
246 break;
247 }
248 default:
249 assert(Loc.getAs<PostStmt>() ||
252 Loc.getAs<CallExitEnd>() ||
253 Loc.getAs<LoopExit>() ||
255 HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
256 break;
257 }
258}
259
260void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
261 const CFGBlock *Blk = L.getDst();
262 NodeBuilderContext BuilderCtx(*this, Blk, Pred);
263
264 // Mark this block as visited.
265 const LocationContext *LC = Pred->getLocationContext();
266 FunctionSummaries->markVisitedBasicBlock(Blk->getBlockID(),
267 LC->getDecl(),
268 LC->getCFG()->getNumBlockIDs());
269
270 // Display a prunable path note to the user if it's a virtual bases branch
271 // and we're taking the path that skips virtual base constructors.
273 L.getDst() == *L.getSrc()->succ_begin()) {
274 ProgramPoint P = L.withTag(getDataTags().make<NoteTag>(
275 [](BugReporterContext &, PathSensitiveBugReport &) -> std::string {
276 // TODO: Just call out the name of the most derived class
277 // when we know it.
278 return "Virtual base initialization skipped because "
279 "it has already been handled by the most derived class";
280 },
281 /*IsPrunable=*/true));
282 // Perform the transition.
283 ExplodedNodeSet Dst;
284 NodeBuilder Bldr(Pred, Dst, BuilderCtx);
285 Pred = Bldr.generateNode(P, Pred->getState(), Pred);
286 if (!Pred)
287 return;
288 }
289
290 // Check if we are entering the EXIT block.
291 if (Blk == &(L.getLocationContext()->getCFG()->getExit())) {
292 assert(L.getLocationContext()->getCFG()->getExit().empty() &&
293 "EXIT block cannot contain Stmts.");
294
295 // Get return statement..
296 const ReturnStmt *RS = nullptr;
297 if (!L.getSrc()->empty()) {
298 CFGElement LastElement = L.getSrc()->back();
299 if (std::optional<CFGStmt> LastStmt = LastElement.getAs<CFGStmt>()) {
300 RS = dyn_cast<ReturnStmt>(LastStmt->getStmt());
301 } else if (std::optional<CFGAutomaticObjDtor> AutoDtor =
302 LastElement.getAs<CFGAutomaticObjDtor>()) {
303 RS = dyn_cast<ReturnStmt>(AutoDtor->getTriggerStmt());
304 }
305 }
306
307 ExplodedNodeSet CheckerNodes;
308 BlockEntrance BE(L.getSrc(), L.getDst(), Pred->getLocationContext());
309 ExprEng.runCheckersForBlockEntrance(BuilderCtx, BE, Pred, CheckerNodes);
310
311 // Process the final state transition.
312 for (ExplodedNode *P : CheckerNodes) {
313 ExprEng.processEndOfFunction(BuilderCtx, P, RS);
314 }
315
316 // This path is done. Don't enqueue any more nodes.
317 return;
318 }
319
320 // Call into the ExprEngine to process entering the CFGBlock.
321 BlockEntrance BE(L.getSrc(), L.getDst(), Pred->getLocationContext());
322 ExplodedNodeSet DstNodes;
323 NodeBuilder Builder(Pred, DstNodes, BuilderCtx);
324 ExprEng.processCFGBlockEntrance(L, BE, Builder, Pred);
325
326 // Auto-generate a node.
327 if (!Builder.hasGeneratedNodes()) {
328 Builder.generateNode(BE, Pred->State, Pred);
329 }
330
331 ExplodedNodeSet CheckerNodes;
332 for (auto *N : DstNodes) {
333 ExprEng.runCheckersForBlockEntrance(BuilderCtx, BE, N, CheckerNodes);
334 }
335
336 // Enqueue nodes onto the worklist.
337 enqueue(CheckerNodes);
338}
339
340void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
341 ExplodedNode *Pred) {
342 // Increment the block counter.
343 const LocationContext *LC = Pred->getLocationContext();
344 unsigned BlockId = L.getBlock()->getBlockID();
345 BlockCounter Counter = WList->getBlockCounter();
346 Counter = BCounterFactory.IncrementCount(Counter, LC->getStackFrame(),
347 BlockId);
348 setBlockCounter(Counter);
349
350 // Process the entrance of the block.
351 if (std::optional<CFGElement> E = L.getFirstElement()) {
352 NodeBuilderContext Ctx(*this, L.getBlock(), Pred);
353 ExprEng.processCFGElement(*E, Pred, 0, &Ctx);
354 } else
355 HandleBlockExit(L.getBlock(), Pred);
356}
357
358void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
359 if (const Stmt *Term = B->getTerminatorStmt()) {
360 switch (Term->getStmtClass()) {
361 default:
362 llvm_unreachable("Analysis for this terminator not implemented.");
363
364 case Stmt::CXXBindTemporaryExprClass:
365 HandleCleanupTemporaryBranch(
366 cast<CXXBindTemporaryExpr>(Term), B, Pred);
367 return;
368
369 // Model static initializers.
370 case Stmt::DeclStmtClass:
371 HandleStaticInit(cast<DeclStmt>(Term), B, Pred);
372 return;
373
374 case Stmt::BinaryOperatorClass: // '&&' and '||'
375 HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
376 return;
377
378 case Stmt::BinaryConditionalOperatorClass:
379 case Stmt::ConditionalOperatorClass:
380 HandleBranch(cast<AbstractConditionalOperator>(Term)->getCond(),
381 Term, B, Pred);
382 return;
383
384 // FIXME: Use constant-folding in CFG construction to simplify this
385 // case.
386
387 case Stmt::ChooseExprClass:
388 HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
389 return;
390
391 case Stmt::CXXTryStmtClass:
392 // Generate a node for each of the successors.
393 // Our logic for EH analysis can certainly be improved.
394 for (const CFGBlock *Succ : B->succs()) {
395 if (Succ) {
396 BlockEdge BE(B, Succ, Pred->getLocationContext());
397 if (ExplodedNode *N = makeNode(BE, Pred->State, Pred))
398 WList->enqueue(N);
399 }
400 }
401 return;
402
403 case Stmt::DoStmtClass:
404 HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
405 return;
406
407 case Stmt::CXXForRangeStmtClass:
408 HandleBranch(cast<CXXForRangeStmt>(Term)->getCond(), Term, B, Pred);
409 return;
410
411 case Stmt::ForStmtClass:
412 HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
413 return;
414
415 case Stmt::SEHLeaveStmtClass:
416 case Stmt::ContinueStmtClass:
417 case Stmt::BreakStmtClass:
418 case Stmt::GotoStmtClass:
419 break;
420
421 case Stmt::IfStmtClass:
422 HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
423 return;
424
425 case Stmt::IndirectGotoStmtClass: {
426 // Only 1 successor: the indirect goto dispatch block.
427 assert(B->succ_size() == 1);
428 NodeBuilderContext Ctx(*this, B, Pred);
429 ExplodedNodeSet Dst;
431 Dst, Ctx, cast<IndirectGotoStmt>(Term)->getTarget(),
432 *(B->succ_begin()));
433
434 ExprEng.processIndirectGoto(Builder, Pred);
435 // Enqueue the new frontier onto the worklist.
436 enqueue(Dst);
437 return;
438 }
439
440 case Stmt::ObjCForCollectionStmtClass:
441 // In the case of ObjCForCollectionStmt, it appears twice in a CFG:
442 //
443 // (1) inside a basic block, which represents the binding of the
444 // 'element' variable to a value.
445 // (2) in a terminator, which represents the branch.
446 //
447 // For (1), ExprEngine will bind a value (i.e., 0 or 1) indicating
448 // whether or not collection contains any more elements. We cannot
449 // just test to see if the element is nil because a container can
450 // contain nil elements.
451 HandleBranch(Term, Term, B, Pred);
452 return;
453
454 case Stmt::SwitchStmtClass: {
455 NodeBuilderContext Ctx(*this, B, Pred);
456 ExplodedNodeSet Dst;
457 ExprEng.processSwitch(Ctx, cast<SwitchStmt>(Term), Pred, Dst);
458 // Enqueue the new frontier onto the worklist.
459 enqueue(Dst);
460 return;
461 }
462
463 case Stmt::WhileStmtClass:
464 HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
465 return;
466
467 case Stmt::GCCAsmStmtClass:
468 assert(cast<GCCAsmStmt>(Term)->isAsmGoto() && "Encountered GCCAsmStmt without labels");
469 // TODO: Handle jumping to labels
470 return;
471 }
472 }
473
475 HandleVirtualBaseBranch(B, Pred);
476 return;
477 }
478
479 assert(B->succ_size() == 1 &&
480 "Blocks with no terminator should have at most 1 successor.");
481
482 BlockEdge BE(B, *(B->succ_begin()), Pred->getLocationContext());
483 if (ExplodedNode *N = makeNode(BE, Pred->State, Pred))
484 WList->enqueue(N);
485}
486
487void CoreEngine::HandleCallEnter(const CallEnter &CE, ExplodedNode *Pred) {
488 NodeBuilderContext BuilderCtx(*this, CE.getEntry(), Pred);
489 ExprEng.processCallEnter(BuilderCtx, CE, Pred);
490}
491
492void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term,
493 const CFGBlock * B, ExplodedNode *Pred) {
494 assert(B->succ_size() == 2);
495 NodeBuilderContext Ctx(*this, B, Pred);
496 ExplodedNodeSet Dst;
497 ExprEng.processBranch(Cond, Ctx, 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 NodeBuilderContext Ctx(*this, B, Pred);
509 ExplodedNodeSet Dst;
510 ExprEng.processCleanupTemporaryBranch(BTE, Ctx, Pred, Dst, *(B->succ_begin()),
511 *(B->succ_begin() + 1));
512 // Enqueue the new frontier onto the worklist.
513 enqueue(Dst);
514}
515
516void CoreEngine::HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
517 ExplodedNode *Pred) {
518 assert(B->succ_size() == 2);
519 NodeBuilderContext Ctx(*this, B, Pred);
520 ExplodedNodeSet Dst;
521 ExprEng.processStaticInitializer(DS, Ctx, Pred, Dst,
522 *(B->succ_begin()), *(B->succ_begin()+1));
523 // Enqueue the new frontier onto the worklist.
524 enqueue(Dst);
525}
526
527void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
528 ExplodedNode *Pred) {
529 assert(B);
530 assert(!B->empty());
531
532 // We no-op by skipping any FullExprCleanup
533 while (StmtIdx < B->size() &&
534 (*B)[StmtIdx].getKind() == CFGElement::FullExprCleanup) {
535 StmtIdx++;
536 }
537
538 if (StmtIdx == B->size())
539 HandleBlockExit(B, Pred);
540 else {
541 NodeBuilderContext Ctx(*this, B, Pred);
542 ExprEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx);
543 }
544}
545
546void CoreEngine::HandleVirtualBaseBranch(const CFGBlock *B,
547 ExplodedNode *Pred) {
548 const LocationContext *LCtx = Pred->getLocationContext();
549 if (const auto *CallerCtor = dyn_cast_or_null<CXXConstructExpr>(
550 LCtx->getStackFrame()->getCallSite())) {
551 switch (CallerCtor->getConstructionKind()) {
554 BlockEdge Loc(B, *B->succ_begin(), LCtx);
555 HandleBlockEdge(Loc, Pred);
556 return;
557 }
558 default:
559 break;
560 }
561 }
562
563 // We either don't see a parent stack frame because we're in the top frame,
564 // or the parent stack frame doesn't initialize our virtual bases.
565 BlockEdge Loc(B, *(B->succ_begin() + 1), LCtx);
566 HandleBlockEdge(Loc, Pred);
567}
568
570 ProgramStateRef State, ExplodedNode *Pred,
571 bool MarkAsSink) const {
572 MarkAsSink = MarkAsSink || State->isPosteriorlyOverconstrained();
573
574 bool IsNew;
575 ExplodedNode *N = G.getNode(Loc, State, MarkAsSink, &IsNew);
576 N->addPredecessor(Pred, G);
577
578 return IsNew ? N : nullptr;
579}
580
582 const CFGBlock *Block, unsigned Idx) {
583 assert(Block);
584 assert(!N->isSink());
585
586 // Check if this node entered a callee.
587 if (N->getLocation().getAs<CallEnter>()) {
588 // Still use the index of the CallExpr. It's needed to create the callee
589 // StackFrameContext.
590 WList->enqueue(N, Block, Idx);
591 return;
592 }
593
594 // Do not create extra nodes. Move to the next CFG element.
595 if (N->getLocation().getAs<PostInitializer>() ||
597 N->getLocation().getAs<LoopExit>()) {
598 WList->enqueue(N, Block, Idx+1);
599 return;
600 }
601
602 if (N->getLocation().getAs<EpsilonPoint>()) {
603 WList->enqueue(N, Block, Idx);
604 return;
605 }
606
607 if ((*Block)[Idx].getKind() == CFGElement::NewAllocator) {
608 WList->enqueue(N, Block, Idx+1);
609 return;
610 }
611
612 // At this point, we know we're processing a normal statement.
613 CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>();
615
616 if (Loc == N->getLocation().withTag(nullptr)) {
617 // Note: 'N' should be a fresh node because otherwise it shouldn't be
618 // a member of Deferred.
619 WList->enqueue(N, Block, Idx+1);
620 return;
621 }
622
623 ExplodedNode *Succ = makeNode(Loc, N->getState(), N);
624
625 if (Succ)
626 WList->enqueue(Succ, Block, Idx+1);
627}
628
629std::optional<unsigned>
630CoreEngine::getCompletedIterationCount(const CFGBlock *B,
631 ExplodedNode *Pred) const {
632 const LocationContext *LC = Pred->getLocationContext();
633 BlockCounter Counter = WList->getBlockCounter();
634 unsigned BlockCount =
635 Counter.getNumVisited(LC->getStackFrame(), B->getBlockID());
636
637 const Stmt *Term = B->getTerminatorStmt();
639 assert(BlockCount >= 1 &&
640 "Block count of currently analyzed block must be >= 1");
641 return BlockCount - 1;
642 }
643 if (isa<DoStmt>(Term)) {
644 // In a do-while loop one iteration happens before the first evaluation of
645 // the loop condition, so we don't subtract one.
646 return BlockCount;
647 }
648 // ObjCForCollectionStmt is skipped intentionally because the current
649 // application of the iteration counts is not relevant for it.
650 return std::nullopt;
651}
652
654 for (const auto I : Set)
655 WList->enqueue(I);
656}
657
659 unsigned Idx) {
660 for (const auto I : Set)
661 enqueueStmtNode(I, Block, Idx);
662}
663
665 for (ExplodedNode *Node : Set) {
666 const LocationContext *LocCtx = Node->getLocationContext();
667
668 // If we are in an inlined call, generate CallExitBegin node.
669 if (LocCtx->getParent()) {
670 // Use the callee location context.
672 if (ExplodedNode *Succ = makeNode(Loc, Node->getState(), Node))
673 WList->enqueue(Succ);
674 } else {
675 // TODO: We should run remove dead bindings here.
676 G.addEndOfPath(Node);
677 NumPathsExplored++;
678 }
679 }
680}
681
683 ProgramStateRef State,
684 ExplodedNode *FromN, bool MarkAsSink) {
685 HasGeneratedNodes = true;
686 Frontier.erase(FromN);
687 ExplodedNode *N = C.getEngine().makeNode(Loc, State, FromN, MarkAsSink);
688
689 Frontier.Add(N);
690
691 return N;
692}
693
695 bool Branch,
696 ExplodedNode *NodePred) {
697 const CFGBlock *Dst = Branch ? DstT : DstF;
698
699 if (!Dst)
700 return nullptr;
701
703 BlockEdge(C.getBlock(), Dst, NodePred->getLocationContext());
704 ExplodedNode *Succ = NodeBuilder::generateNode(Loc, State, NodePred);
705 return Succ;
706}
707
710 ExplodedNode *Pred) {
711 BlockEdge BE(C.getBlock(), Block, Pred->getLocationContext());
712 return generateNode(BE, St, Pred);
713}
714
717 ExplodedNode *Pred) {
718 BlockEdge BE(C.getBlock(), Block, Pred->getLocationContext());
719 return generateNode(BE, St, Pred);
720}
721
723 ExplodedNode *Pred) {
724 // Get the block for the default case.
725 const CFGBlock *Src = C.getBlock();
726 assert(Src->succ_rbegin() != Src->succ_rend());
727 CFGBlock *DefaultBlock = *Src->succ_rbegin();
728
729 // Basic correctness check for default blocks that are unreachable and not
730 // caught by earlier stages.
731 if (!DefaultBlock)
732 return nullptr;
733
734 BlockEdge BE(Src, DefaultBlock, Pred->getLocationContext());
735 return generateNode(BE, St, Pred);
736}
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:858
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 C++ object destructor implicitly generated for automatic object or temporary bound to cons...
Definition CFG.h:445
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:190
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:53
friend class IndirectGotoNodeBuilder
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.
friend class NodeBuilderContext
Definition CoreEngine.h:54
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.
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 markVisitedBasicBlock(unsigned ID, const Decl *D, unsigned TotalIDs)
ExplodedNode * generateNode(const CFGBlock *Block, ProgramStateRef State, ExplodedNode *Pred)
const NodeBuilderContext & C
Definition CoreEngine.h:248
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:254
NodeBuilder(ExplodedNodeSet &DstSet, const NodeBuilderContext &Ctx)
Definition CoreEngine.h:257
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