31#include "llvm/Support/ErrorHandling.h"
32#include "llvm/Support/FormatVariadic.h"
33#include "llvm/Support/TimeProfiler.h"
43#define DEBUG_TYPE "CoreEngine"
49 "The # of times we reached the max number of steps.");
50STAT_COUNTER(NumPathsExplored,
"The # of paths explored by the analyzer.");
71 llvm_unreachable(
"Unknown AnalyzerOptions::ExplorationStrategyKind");
78 BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {}
81 WList->setBlockCounter(
C);
83 CTUWList->setBlockCounter(
C);
90 assert(!G.getRoot() &&
"empty graph must not have a root node");
95 assert(Entry->
empty() &&
"Entry block must be empty.");
97 assert(Entry->
succ_size() == 1 &&
"Entry block must have 1 successor.");
100 FunctionSummaries->markVisitedBasicBlock(Entry->
getBlockID(),
112 setBlockCounter(BCounterFactory.GetEmptyCounter());
115 InitState = ExprEng.getInitialState(L);
118 ExplodedNode *Node = G.getNode(StartLoc, InitState,
false, &IsNew);
120 G.designateAsRoot(Node);
125 ExprEng.processBeginOfFunction(Node, DstBegin, StartLoc);
131 bool UnlimitedSteps = MaxSteps == 0;
135 const unsigned PreReservationCap = 4000000;
137 G.reserve(std::min(MaxSteps, PreReservationCap));
139 auto ProcessWList = [
this, UnlimitedSteps](
unsigned MaxSteps) {
140 unsigned Steps = MaxSteps;
141 while (WList->hasWork()) {
142 if (!UnlimitedSteps) {
144 NumReachedMaxSteps++;
162 return MaxSteps - Steps;
164 const unsigned STUSteps = ProcessWList(MaxSteps);
167 NumSTUSteps += STUSteps;
168 const unsigned MinCTUSteps =
169 this->ExprEng.getAnalysisManager().options.CTUMaxNodesMin;
171 this->ExprEng.getAnalysisManager().options.CTUMaxNodesPercentage;
172 unsigned MaxCTUSteps = std::max(STUSteps * Pct / 100, MinCTUSteps);
174 WList = std::move(CTUWList);
175 const unsigned CTUSteps = ProcessWList(MaxCTUSteps);
176 NumCTUSteps += CTUSteps;
179 ExprEng.processEndWorklist();
180 return WList->hasWork();
184 if (llvm::timeTraceProfilerEnabled()) {
185 return llvm::formatv(
"dispatchWorkItem {0}",
195 assert(llvm::timeTraceProfilerEnabled());
196 std::string Detail =
"";
198 if (
const Stmt *S = SP->getStmt())
199 Detail = S->getStmtClassName();
201 auto SLoc =
Loc.getSourceLocation();
203 return llvm::TimeTraceMetadata{std::move(Detail),
""};
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)};
226 ExprEng.resetCurrLocationContextAndBlock();
239 assert(
false &&
"BlockExit location never occur in forward analysis.");
247 ExprEng.processCallExit(Pred);
252 "Assume epsilon has exactly one predecessor by construction");
287 return "Virtual base initialization skipped because "
288 "it has already been handled by the most derived class";
299 if (Blk == &ExitBlk) {
300 assert(ExitBlk.
empty() &&
"EXIT block cannot contain Stmts.");
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());
314 ExplodedNodeSet CheckerNodes;
316 ExprEng.runCheckersForBlockEntrance(BE, Pred, CheckerNodes);
319 for (ExplodedNode *P : CheckerNodes) {
320 ExprEng.processEndOfFunction(P, RS);
329 ExplodedNodeSet DstNodes;
330 NodeBuilder Builder(Pred, DstNodes, ExprEng.getBuilderContext());
331 ExprEng.processCFGBlockEntrance(L, BE, Builder, Pred);
334 if (!Builder.hasGeneratedNodes()) {
335 Builder.generateNode(BE, Pred->State, Pred);
338 ExplodedNodeSet CheckerNodes;
339 for (
auto *N : DstNodes) {
340 ExprEng.runCheckersForBlockEntrance(BE, N, CheckerNodes);
347void CoreEngine::HandleBlockEntrance(
const BlockEntrance &L,
352 BlockCounter Counter = WList->getBlockCounter();
353 Counter = BCounterFactory.IncrementCount(Counter, LC->
getStackFrame(),
355 setBlockCounter(Counter);
361 ExprEng.processCFGElement(*E, Pred, 0);
363 HandleBlockExit(L.
getBlock(), Pred);
366void CoreEngine::HandleBlockExit(
const CFGBlock * B,
ExplodedNode *Pred) {
370 switch (Term->getStmtClass()) {
372 llvm_unreachable(
"Analysis for this terminator not implemented.");
374 case Stmt::CXXBindTemporaryExprClass:
375 HandleCleanupTemporaryBranch(
380 case Stmt::DeclStmtClass:
384 case Stmt::BinaryOperatorClass:
388 case Stmt::BinaryConditionalOperatorClass:
389 case Stmt::ConditionalOperatorClass:
397 case Stmt::ChooseExprClass:
401 case Stmt::CXXTryStmtClass:
404 for (
const CFGBlock *Succ : B->
succs()) {
407 if (ExplodedNode *N =
makeNode(BE, Pred->State, Pred))
413 case Stmt::DoStmtClass:
414 HandleBranch(
cast<DoStmt>(Term)->getCond(), Term, B, Pred);
417 case Stmt::CXXForRangeStmtClass:
421 case Stmt::ForStmtClass:
425 case Stmt::SEHLeaveStmtClass:
426 case Stmt::ContinueStmtClass:
427 case Stmt::BreakStmtClass:
428 case Stmt::GotoStmtClass:
431 case Stmt::IfStmtClass:
432 HandleBranch(
cast<IfStmt>(Term)->getCond(), Term, B, Pred);
435 case Stmt::IndirectGotoStmtClass: {
439 ExprEng.processIndirectGoto(Dst,
446 case Stmt::ObjCForCollectionStmtClass:
457 HandleBranch(Term, Term, B, Pred);
460 case Stmt::SwitchStmtClass: {
468 case Stmt::WhileStmtClass:
472 case Stmt::GCCAsmStmtClass:
473 assert(
cast<GCCAsmStmt>(Term)->isAsmGoto() &&
"Encountered GCCAsmStmt without labels");
480 HandleVirtualBaseBranch(B, Pred);
485 "Blocks with no terminator should have at most 1 successor.");
488 if (ExplodedNode *N =
makeNode(BE, Pred->State, Pred))
492void CoreEngine::HandleCallEnter(
const CallEnter &CE,
ExplodedNode *Pred) {
495 ExprEng.processCallEnter(CE, Pred);
498void CoreEngine::HandleBranch(
const Stmt *
Cond,
const Stmt *Term,
504 getCompletedIterationCount(B, Pred));
509void CoreEngine::HandleCleanupTemporaryBranch(
const CXXBindTemporaryExpr *BTE,
514 ExprEng.processCleanupTemporaryBranch(BTE, Pred, Dst, *(B->
succ_begin()),
520void CoreEngine::HandleStaticInit(
const DeclStmt *DS,
const CFGBlock *B,
524 ExprEng.processStaticInitializer(DS, Pred, Dst, *(B->
succ_begin()),
530void CoreEngine::HandlePostStmt(
const CFGBlock *B,
unsigned StmtIdx,
536 while (StmtIdx < B->size() &&
541 if (StmtIdx == B->
size())
542 HandleBlockExit(B, Pred);
545 ExprEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx);
549void CoreEngine::HandleVirtualBaseBranch(
const CFGBlock *B,
552 if (
const auto *CallerCtor = dyn_cast_or_null<CXXConstructExpr>(
554 switch (CallerCtor->getConstructionKind()) {
558 HandleBlockEdge(Loc, Pred);
568 BlockEdge Loc(B, *(B->
succ_begin() + 1), LCtx);
569 HandleBlockEdge(Loc, Pred);
574 bool MarkAsSink)
const {
575 MarkAsSink = MarkAsSink || State->isPosteriorlyOverconstrained();
581 return IsNew ? N :
nullptr;
593 WList->enqueue(N,
Block, Idx);
601 WList->enqueue(N,
Block, Idx+1);
606 WList->enqueue(N,
Block, Idx);
611 WList->enqueue(N,
Block, Idx+1);
622 WList->enqueue(N,
Block, Idx+1);
629 WList->enqueue(Succ,
Block, Idx+1);
632std::optional<unsigned>
633CoreEngine::getCompletedIterationCount(
const CFGBlock *B,
637 unsigned BlockCount =
642 assert(BlockCount >= 1 &&
643 "Block count of currently analyzed block must be >= 1");
644 return BlockCount - 1;
657 for (
const auto I :
Set)
663 for (
const auto I :
Set)
676 WList->enqueue(Succ);
679 G.addEndOfPath(Node);
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.
SourceManager & getSourceManager()
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.
CFGTerminator getTerminator() const
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
unsigned getBlockID() const
unsigned succ_size() const
Represents a top-level expression in a basic block.
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type.
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
const Stmt * getStmt() const
bool isVirtualBaseBranch() const
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
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.
const Decl * getDecl() const
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
const LocationContext * getParent() const
It might return null.
const StackFrame * 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;.
const Expr * getCallSite() const
Stmt - This represents one statement.
An abstract data type used to count the number of times a given block has been visited along a path a...
unsigned getNumVisited(const StackFrame *CallSite, unsigned BlockID) const
CoreEngine(ExprEngine &exprengine, FunctionSummariesTy *FS, AnalyzerOptions &Opts)
Construct a CoreEngine object to analyze the provided CFG.
DataTag::Factory & getDataTags()
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.
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 ...
bool hasSinglePred() const
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
void setCurrLocationContextAndBlock(const LocationContext *LC, const CFGBlock *B)
void markVisitedBasicBlock(unsigned ID, const Decl *D, unsigned TotalIDs)
const NodeBuilderContext & C
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.
While alive, includes the current analysis stack in a crash trace.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
ExplodedNode * getNode() const
Returns the node associated with the worklist unit.
unsigned getIndex() const
Return the index within the CFGBlock for the worklist unit.
const CFGBlock * getBlock() const
Returns the CFGblock associated with the worklist unit.
BlockCounter getBlockCounter() const
Returns the block counter map associated with the worklist unit.
static std::unique_ptr< WorkList > makeUnexploredFirstPriorityLocationQueue()
static std::unique_ptr< WorkList > makeUnexploredFirstPriorityQueue()
static std::unique_ptr< WorkList > makeBFSBlockDFSContents()
static std::unique_ptr< WorkList > makeBFS()
static std::unique_ptr< WorkList > makeDFS()
static std::unique_ptr< WorkList > makeUnexploredFirst()
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
U cast(CodeGen::Address addr)
@ UnexploredFirstLocationQueue