clang 22.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
56static std::unique_ptr<WorkList> generateWorkList(AnalyzerOptions &Opts) {
57 switch (Opts.getExplorationStrategy()) {
58 case ExplorationStrategyKind::DFS:
59 return WorkList::makeDFS();
60 case ExplorationStrategyKind::BFS:
61 return WorkList::makeBFS();
62 case ExplorationStrategyKind::BFSBlockDFSContents:
64 case ExplorationStrategyKind::UnexploredFirst:
66 case ExplorationStrategyKind::UnexploredFirstQueue:
68 case ExplorationStrategyKind::UnexploredFirstLocationQueue:
70 }
71 llvm_unreachable("Unknown AnalyzerOptions::ExplorationStrategyKind");
72}
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);
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 NodeBuilderWithSinks NodeBuilder(Pred, DstNodes, BuilderCtx, BE);
324 ExprEng.processCFGBlockEntrance(L, NodeBuilder, Pred);
325
326 // Auto-generate a node.
328 NodeBuilder.generateNode(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.
395 et = B->succ_end(); it != et; ++it) {
396 if (const CFGBlock *succ = *it) {
397 generateNode(BlockEdge(B, succ, Pred->getLocationContext()),
398 Pred->State, Pred);
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
430 builder(Pred, B, cast<IndirectGotoStmt>(Term)->getTarget(),
431 *(B->succ_begin()), this);
432
433 ExprEng.processIndirectGoto(builder);
434 return;
435 }
436
437 case Stmt::ObjCForCollectionStmtClass:
438 // In the case of ObjCForCollectionStmt, it appears twice in a CFG:
439 //
440 // (1) inside a basic block, which represents the binding of the
441 // 'element' variable to a value.
442 // (2) in a terminator, which represents the branch.
443 //
444 // For (1), ExprEngine will bind a value (i.e., 0 or 1) indicating
445 // whether or not collection contains any more elements. We cannot
446 // just test to see if the element is nil because a container can
447 // contain nil elements.
448 HandleBranch(Term, Term, B, Pred);
449 return;
450
451 case Stmt::SwitchStmtClass: {
452 SwitchNodeBuilder builder(Pred, B, cast<SwitchStmt>(Term)->getCond(),
453 this);
454
455 ExprEng.processSwitch(builder);
456 return;
457 }
458
459 case Stmt::WhileStmtClass:
460 HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
461 return;
462
463 case Stmt::GCCAsmStmtClass:
464 assert(cast<GCCAsmStmt>(Term)->isAsmGoto() && "Encountered GCCAsmStmt without labels");
465 // TODO: Handle jumping to labels
466 return;
467 }
468 }
469
471 HandleVirtualBaseBranch(B, Pred);
472 return;
473 }
474
475 assert(B->succ_size() == 1 &&
476 "Blocks with no terminator should have at most 1 successor.");
477
478 generateNode(BlockEdge(B, *(B->succ_begin()), Pred->getLocationContext()),
479 Pred->State, Pred);
480}
481
482void CoreEngine::HandleCallEnter(const CallEnter &CE, ExplodedNode *Pred) {
483 NodeBuilderContext BuilderCtx(*this, CE.getEntry(), Pred);
484 ExprEng.processCallEnter(BuilderCtx, CE, Pred);
485}
486
487void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term,
488 const CFGBlock * B, ExplodedNode *Pred) {
489 assert(B->succ_size() == 2);
490 NodeBuilderContext Ctx(*this, B, Pred);
491 ExplodedNodeSet Dst;
492 ExprEng.processBranch(Cond, Ctx, Pred, Dst, *(B->succ_begin()),
493 *(B->succ_begin() + 1),
494 getCompletedIterationCount(B, Pred));
495 // Enqueue the new frontier onto the worklist.
496 enqueue(Dst);
497}
498
499void CoreEngine::HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
500 const CFGBlock *B,
501 ExplodedNode *Pred) {
502 assert(B->succ_size() == 2);
503 NodeBuilderContext Ctx(*this, B, Pred);
504 ExplodedNodeSet Dst;
505 ExprEng.processCleanupTemporaryBranch(BTE, Ctx, Pred, Dst, *(B->succ_begin()),
506 *(B->succ_begin() + 1));
507 // Enqueue the new frontier onto the worklist.
508 enqueue(Dst);
509}
510
511void CoreEngine::HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
512 ExplodedNode *Pred) {
513 assert(B->succ_size() == 2);
514 NodeBuilderContext Ctx(*this, B, Pred);
515 ExplodedNodeSet Dst;
516 ExprEng.processStaticInitializer(DS, Ctx, Pred, Dst,
517 *(B->succ_begin()), *(B->succ_begin()+1));
518 // Enqueue the new frontier onto the worklist.
519 enqueue(Dst);
520}
521
522void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
523 ExplodedNode *Pred) {
524 assert(B);
525 assert(!B->empty());
526
527 if (StmtIdx == B->size())
528 HandleBlockExit(B, Pred);
529 else {
530 NodeBuilderContext Ctx(*this, B, Pred);
531 ExprEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx);
532 }
533}
534
535void CoreEngine::HandleVirtualBaseBranch(const CFGBlock *B,
536 ExplodedNode *Pred) {
537 const LocationContext *LCtx = Pred->getLocationContext();
538 if (const auto *CallerCtor = dyn_cast_or_null<CXXConstructExpr>(
539 LCtx->getStackFrame()->getCallSite())) {
540 switch (CallerCtor->getConstructionKind()) {
543 BlockEdge Loc(B, *B->succ_begin(), LCtx);
544 HandleBlockEdge(Loc, Pred);
545 return;
546 }
547 default:
548 break;
549 }
550 }
551
552 // We either don't see a parent stack frame because we're in the top frame,
553 // or the parent stack frame doesn't initialize our virtual bases.
554 BlockEdge Loc(B, *(B->succ_begin() + 1), LCtx);
555 HandleBlockEdge(Loc, Pred);
556}
557
558/// generateNode - Utility method to generate nodes, hook up successors,
559/// and add nodes to the worklist.
560void CoreEngine::generateNode(const ProgramPoint &Loc,
561 ProgramStateRef State,
562 ExplodedNode *Pred) {
563 assert(Pred);
564 bool IsNew;
565 ExplodedNode *Node = G.getNode(Loc, State, false, &IsNew);
566
567 Node->addPredecessor(Pred, G); // Link 'Node' with its predecessor.
568
569 // Only add 'Node' to the worklist if it was freshly generated.
570 if (IsNew) WList->enqueue(Node);
571}
572
574 const CFGBlock *Block, unsigned Idx) {
575 assert(Block);
576 assert(!N->isSink());
577
578 // Check if this node entered a callee.
579 if (N->getLocation().getAs<CallEnter>()) {
580 // Still use the index of the CallExpr. It's needed to create the callee
581 // StackFrameContext.
582 WList->enqueue(N, Block, Idx);
583 return;
584 }
585
586 // Do not create extra nodes. Move to the next CFG element.
587 if (N->getLocation().getAs<PostInitializer>() ||
589 N->getLocation().getAs<LoopExit>()) {
590 WList->enqueue(N, Block, Idx+1);
591 return;
592 }
593
594 if (N->getLocation().getAs<EpsilonPoint>()) {
595 WList->enqueue(N, Block, Idx);
596 return;
597 }
598
599 if ((*Block)[Idx].getKind() == CFGElement::NewAllocator) {
600 WList->enqueue(N, Block, Idx+1);
601 return;
602 }
603
604 // At this point, we know we're processing a normal statement.
605 CFGStmt CS = (*Block)[Idx].castAs<CFGStmt>();
607
608 if (Loc == N->getLocation().withTag(nullptr)) {
609 // Note: 'N' should be a fresh node because otherwise it shouldn't be
610 // a member of Deferred.
611 WList->enqueue(N, Block, Idx+1);
612 return;
613 }
614
615 bool IsNew;
616 ExplodedNode *Succ = G.getNode(Loc, N->getState(), false, &IsNew);
617 Succ->addPredecessor(N, G);
618
619 if (IsNew)
620 WList->enqueue(Succ, Block, Idx+1);
621}
622
623ExplodedNode *CoreEngine::generateCallExitBeginNode(ExplodedNode *N,
624 const ReturnStmt *RS) {
625 // Create a CallExitBegin node and enqueue it.
626 const auto *LocCtx = cast<StackFrameContext>(N->getLocationContext());
627
628 // Use the callee location context.
629 CallExitBegin Loc(LocCtx, RS);
630
631 bool isNew;
632 ExplodedNode *Node = G.getNode(Loc, N->getState(), false, &isNew);
633 Node->addPredecessor(N, G);
634 return isNew ? Node : nullptr;
635}
636
637std::optional<unsigned>
638CoreEngine::getCompletedIterationCount(const CFGBlock *B,
639 ExplodedNode *Pred) const {
640 const LocationContext *LC = Pred->getLocationContext();
641 BlockCounter Counter = WList->getBlockCounter();
642 unsigned BlockCount =
643 Counter.getNumVisited(LC->getStackFrame(), B->getBlockID());
644
645 const Stmt *Term = B->getTerminatorStmt();
646 if (isa<ForStmt, WhileStmt, CXXForRangeStmt>(Term)) {
647 assert(BlockCount >= 1 &&
648 "Block count of currently analyzed block must be >= 1");
649 return BlockCount - 1;
650 }
651 if (isa<DoStmt>(Term)) {
652 // In a do-while loop one iteration happens before the first evaluation of
653 // the loop condition, so we don't subtract one.
654 return BlockCount;
655 }
656 // ObjCForCollectionStmt is skipped intentionally because the current
657 // application of the iteration counts is not relevant for it.
658 return std::nullopt;
659}
660
662 for (const auto I : Set)
663 WList->enqueue(I);
664}
665
667 const CFGBlock *Block, unsigned Idx) {
668 for (const auto I : Set)
669 enqueueStmtNode(I, Block, Idx);
670}
671
673 for (auto *I : Set) {
674 // If we are in an inlined call, generate CallExitBegin node.
675 if (I->getLocationContext()->getParent()) {
676 I = generateCallExitBeginNode(I, RS);
677 if (I)
678 WList->enqueue(I);
679 } else {
680 // TODO: We should run remove dead bindings here.
681 G.addEndOfPath(I);
682 NumPathsExplored++;
683 }
684 }
685}
686
687void NodeBuilder::anchor() {}
688
690 ProgramStateRef State,
691 ExplodedNode *FromN,
692 bool MarkAsSink) {
693 HasGeneratedNodes = true;
694 bool IsNew;
695 ExplodedNode *N = C.getEngine().G.getNode(Loc, State, MarkAsSink, &IsNew);
696 N->addPredecessor(FromN, C.getEngine().G);
697 Frontier.erase(FromN);
698
699 if (!IsNew)
700 return nullptr;
701
702 if (!MarkAsSink)
703 Frontier.Add(N);
704
705 return N;
706}
707
708void NodeBuilderWithSinks::anchor() {}
709
711 if (EnclosingBldr)
712 for (const auto I : Frontier)
713 EnclosingBldr->addNodes(I);
714}
715
716void BranchNodeBuilder::anchor() {}
717
719 bool Branch,
720 ExplodedNode *NodePred) {
721 const CFGBlock *Dst = Branch ? DstT : DstF;
722
723 if (!Dst)
724 return nullptr;
725
727 BlockEdge(C.getBlock(), Dst, NodePred->getLocationContext());
728 ExplodedNode *Succ = generateNodeImpl(Loc, State, NodePred);
729 return Succ;
730}
731
735 bool IsSink) {
736 bool IsNew;
737 ExplodedNode *Succ =
738 Eng.G.getNode(BlockEdge(Src, I.getBlock(), Pred->getLocationContext()),
739 St, IsSink, &IsNew);
740 Succ->addPredecessor(Pred, Eng.G);
741
742 if (!IsNew)
743 return nullptr;
744
745 if (!IsSink)
746 Eng.WList->enqueue(Succ);
747
748 return Succ;
749}
750
753 ProgramStateRef St) {
754 bool IsNew;
755 ExplodedNode *Succ =
756 Eng.G.getNode(BlockEdge(Src, I.getBlock(), Pred->getLocationContext()),
757 St, false, &IsNew);
758 Succ->addPredecessor(Pred, Eng.G);
759 if (!IsNew)
760 return nullptr;
761
762 Eng.WList->enqueue(Succ);
763 return Succ;
764}
765
768 bool IsSink) {
769 // Get the block for the default case.
770 assert(Src->succ_rbegin() != Src->succ_rend());
771 CFGBlock *DefaultBlock = *Src->succ_rbegin();
772
773 // Basic correctness check for default blocks that are unreachable and not
774 // caught by earlier stages.
775 if (!DefaultBlock)
776 return nullptr;
777
778 bool IsNew;
779 ExplodedNode *Succ =
780 Eng.G.getNode(BlockEdge(Src, DefaultBlock, Pred->getLocationContext()),
781 St, IsSink, &IsNew);
782 Succ->addPredecessor(Pred, Eng.G);
783
784 if (!IsNew)
785 return nullptr;
786
787 if (!IsSink)
788 Eng.WList->enqueue(Succ);
789
790 return Succ;
791}
DynTypedNode Node
StringRef P
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
Expr * E
static std::unique_ptr< WorkList > generateWorkList(AnalyzerOptions &Opts)
Definition: CoreEngine.cpp:56
ALWAYS_ENABLED_STATISTIC(NumReachedMaxSteps, "The # of times we reached the max number of steps.")
static std::string timeTraceScopeName(const ProgramPoint &Loc)
Definition: CoreEngine.cpp:182
static llvm::TimeTraceMetadata timeTraceMetadata(const ExplodedNode *Pred, const ProgramPoint &Loc)
Definition: CoreEngine.cpp:191
static Decl::Kind getKind(const Decl *D)
Definition: DeclBase.cpp:1192
#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)
Definition: OffloadArch.cpp:16
SourceManager & getSourceManager()
Definition: ASTContext.h:801
ASTContext & getASTContext() const
Stores options for the analyzer from the command line.
ExplorationStrategyKind getExplorationStrategy() const
const CFGBlock * getSrc() const
Definition: ProgramPoint.h:516
const CFGBlock * getDst() const
Definition: ProgramPoint.h:520
std::optional< CFGElement > getFirstElement() const
Definition: ProgramPoint.h:241
const CFGBlock * getBlock() const
Definition: ProgramPoint.h:237
Represents C++ object destructor implicitly generated for automatic object or temporary bound to cons...
Definition: CFG.h:418
Represents a single basic block in a source-level CFG.
Definition: CFG.h:605
succ_iterator succ_end()
Definition: CFG.h:991
CFGElement back() const
Definition: CFG.h:908
succ_reverse_iterator succ_rend()
Definition: CFG.h:996
unsigned size() const
Definition: CFG.h:952
succ_reverse_iterator succ_rbegin()
Definition: CFG.h:995
bool empty() const
Definition: CFG.h:953
CFGTerminator getTerminator() const
Definition: CFG.h:1085
succ_iterator succ_begin()
Definition: CFG.h:990
Stmt * getTerminatorStmt()
Definition: CFG.h:1087
unsigned getBlockID() const
Definition: CFG.h:1111
AdjacentBlocks::const_iterator const_succ_iterator
Definition: CFG.h:966
unsigned succ_size() const
Definition: CFG.h:1008
Represents a top-level expression in a basic block.
Definition: CFG.h:55
@ NewAllocator
Definition: CFG.h:62
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type.
Definition: CFG.h:99
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:109
const Stmt * getStmt() const
Definition: CFG.h:139
bool isVirtualBaseBranch() const
Definition: CFG.h:574
CFGBlock & getExit()
Definition: CFG.h:1332
CFGBlock & getEntry()
Definition: CFG.h:1330
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Definition: CFG.h:1409
Represents binding an expression to a temporary.
Definition: ExprCXX.h:1494
Represents a point when we begin processing an inlined call.
Definition: ProgramPoint.h:638
const CFGBlock * getEntry() const
Returns the entry block in the CFG for the entered function.
Definition: ProgramPoint.h:653
Represents a point when we start the call exit sequence (for inlined call).
Definition: ProgramPoint.h:676
Represents a point when we finish the call exit sequence (for inlined call).
Definition: ProgramPoint.h:696
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition: Stmt.h:1611
This is a meta program point, which should be skipped by all the diagnostic reasoning etc.
Definition: ProgramPoint.h:740
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 StackFrameContext * getStackFrame() const
Represents a point when we exit a loop.
Definition: ProgramPoint.h:721
Represents a program point just after an implicit call event.
Definition: ProgramPoint.h:607
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 ...
Definition: ProgramPoint.h:135
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
Definition: ProgramPoint.h:153
const LocationContext * getLocationContext() const
Definition: ProgramPoint.h:181
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition: Stmt.h:3160
const Stmt * getCallSite() const
Stmt - This represents one statement.
Definition: Stmt.h:85
BlockCounter IncrementCount(BlockCounter BC, const StackFrameContext *CallSite, unsigned BlockID)
An abstract data type used to count the number of times a given block has been visited along a path a...
Definition: BlockCounter.h:29
unsigned getNumVisited(const StackFrameContext *CallSite, unsigned BlockID) const
ExplodedNode * generateNode(ProgramStateRef State, bool branch, ExplodedNode *Pred)
Definition: CoreEngine.cpp:718
CoreEngine(ExprEngine &exprengine, FunctionSummariesTy *FS, AnalyzerOptions &Opts)
Construct a CoreEngine object to analyze the provided CFG.
Definition: CoreEngine.cpp:74
DataTag::Factory & getDataTags()
Definition: CoreEngine.h:195
void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx)
Enqueue a single node created as a result of statement processing.
Definition: CoreEngine.cpp:573
void dispatchWorkItem(ExplodedNode *Pred, ProgramPoint Loc, const WorkListUnit &WU)
Dispatch the work list item based on the given location information.
Definition: CoreEngine.cpp:213
friend class NodeBuilder
Definition: CoreEngine.h:55
bool ExecuteWorkList(const LocationContext *L, unsigned Steps, ProgramStateRef InitState)
ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
Definition: CoreEngine.cpp:87
void enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS)
enqueue the nodes corresponding to the end of function onto the end of path / work list.
Definition: CoreEngine.cpp:672
void enqueue(ExplodedNodeSet &Set)
Enqueue the given set of nodes onto the work list.
Definition: CoreEngine.cpp:661
void reserve(unsigned NodeCount)
ExplodedNode * getNode(const ProgramPoint &L, ProgramStateRef State, bool IsSink=false, bool *IsNew=nullptr)
Retrieve the node associated with a (Location, State) pair, where the 'Location' is a ProgramPoint in...
ExplodedNode * getRoot() const
Get the root node of the graph.
void designateAsRoot(ExplodedNode *V)
Mark a node as the root of the graph.
ExplodedNode * addEndOfPath(ExplodedNode *V)
addEndOfPath - Add an untyped node to the set of EOP nodes.
bool erase(ExplodedNode *N)
void Add(ExplodedNode *N)
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 processEndOfFunction(NodeBuilderContext &BC, ExplodedNode *Pred, const ReturnStmt *RS=nullptr)
Called by CoreEngine.
void processCallEnter(NodeBuilderContext &BC, CallEnter CE, ExplodedNode *Pred)
Generate the entry node of the callee.
void processBeginOfFunction(NodeBuilderContext &BC, ExplodedNode *Pred, ExplodedNodeSet &Dst, const BlockEdge &L)
Called by CoreEngine.
ProgramStateRef getInitialState(const LocationContext *InitLoc)
getInitialState - Return the initial state used for the root vertex in the ExplodedGraph.
Definition: ExprEngine.cpp:245
void processCallExit(ExplodedNode *Pred)
Generate the sequence of nodes that simulate the call exit and the post visit for CallExpr.
void processCFGBlockEntrance(const BlockEdge &L, NodeBuilderWithSinks &nodeBuilder, ExplodedNode *Pred)
Called by CoreEngine when processing the entrance of a CFGBlock.
void processCFGElement(const CFGElement E, ExplodedNode *Pred, unsigned StmtIdx, NodeBuilderContext *Ctx)
processCFGElement - Called by CoreEngine.
Definition: ExprEngine.cpp:967
void processStaticInitializer(const DeclStmt *DS, NodeBuilderContext &BuilderCtx, ExplodedNode *Pred, ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF)
Called by CoreEngine.
void processBranch(const Stmt *Condition, NodeBuilderContext &BuilderCtx, ExplodedNode *Pred, ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF, std::optional< unsigned > IterationsCompletedInLoop)
ProcessBranch - Called by CoreEngine.
void processSwitch(SwitchNodeBuilder &builder)
ProcessSwitch - Called by CoreEngine.
void processEndWorklist()
Called by CoreEngine when the analysis worklist has terminated.
Definition: ExprEngine.cpp:961
void processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE, NodeBuilderContext &BldCtx, ExplodedNode *Pred, ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF)
Called by CoreEngine.
AnalysisManager & getAnalysisManager()
Definition: ExprEngine.h:198
void runCheckersForBlockEntrance(const NodeBuilderContext &BldCtx, const BlockEntrance &Entrance, ExplodedNode *Pred, ExplodedNodeSet &Dst)
void processIndirectGoto(IndirectGotoNodeBuilder &builder)
processIndirectGoto - Called by CoreEngine.
void markVisitedBasicBlock(unsigned ID, const Decl *D, unsigned TotalIDs)
ExplodedNode * generateNode(const iterator &I, ProgramStateRef State, bool isSink=false)
Definition: CoreEngine.cpp:733
const CoreEngine & getEngine() const
Return the CoreEngine associated with this builder.
Definition: CoreEngine.h:214
const CFGBlock * getBlock() const
Return the CFGBlock associated with this builder.
Definition: CoreEngine.h:217
This node builder keeps track of the generated sink nodes.
Definition: CoreEngine.h:347
This is the simplest builder which generates nodes in the ExplodedGraph.
Definition: CoreEngine.h:240
const NodeBuilderContext & C
Definition: CoreEngine.h:244
ExplodedNode * generateNode(const ProgramPoint &PP, ProgramStateRef State, ExplodedNode *Pred)
Generates a node in the ExplodedGraph.
Definition: CoreEngine.h:293
ExplodedNodeSet & Frontier
The frontier set - a set of nodes which need to be propagated after the builder dies.
Definition: CoreEngine.h:254
void addNodes(const ExplodedNodeSet &S)
Definition: CoreEngine.h:341
ExplodedNode * generateNodeImpl(const ProgramPoint &PP, ProgramStateRef State, ExplodedNode *Pred, bool MarkAsSink=false)
Definition: CoreEngine.cpp:689
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
const CFGBlock * getBlock() const
Definition: CoreEngine.h:543
ExplodedNode * generateDefaultCaseNode(ProgramStateRef State, bool isSink=false)
Definition: CoreEngine.cpp:767
ExplodedNode * generateCaseStmtNode(const iterator &I, ProgramStateRef State)
Definition: CoreEngine.cpp:752
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
The JSON file list parser is used to communicate input to InstallAPI.