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.");
111 setBlockCounter(BCounterFactory.GetEmptyCounter());
114 InitState = ExprEng.getInitialState(SF);
117 ExplodedNode *Node = G.getNode(StartLoc, InitState,
false, &IsNew);
119 G.designateAsRoot(Node);
121 ExprEng.setCurrStackFrameAndBlock(Node->
getStackFrame(), Succ);
124 ExprEng.processBeginOfFunction(Node, DstBegin, StartLoc);
130 bool UnlimitedSteps = MaxSteps == 0;
134 const unsigned PreReservationCap = 4000000;
136 G.reserve(std::min(MaxSteps, PreReservationCap));
138 auto ProcessWList = [
this, UnlimitedSteps](
unsigned MaxSteps) {
139 unsigned Steps = MaxSteps;
140 while (WList->hasWork()) {
141 if (!UnlimitedSteps) {
143 NumReachedMaxSteps++;
161 return MaxSteps - Steps;
163 const unsigned STUSteps = ProcessWList(MaxSteps);
166 NumSTUSteps += STUSteps;
167 const unsigned MinCTUSteps =
168 this->ExprEng.getAnalysisManager().options.CTUMaxNodesMin;
170 this->ExprEng.getAnalysisManager().options.CTUMaxNodesPercentage;
171 unsigned MaxCTUSteps = std::max(STUSteps * Pct / 100, MinCTUSteps);
173 WList = std::move(CTUWList);
174 const unsigned CTUSteps = ProcessWList(MaxCTUSteps);
175 NumCTUSteps += CTUSteps;
178 ExprEng.processEndWorklist();
179 return WList->hasWork();
183 if (llvm::timeTraceProfilerEnabled()) {
184 return llvm::formatv(
"dispatchWorkItem {0}",
194 assert(llvm::timeTraceProfilerEnabled());
195 std::string Detail =
"";
197 if (
const Stmt *S = SP->getStmt())
198 Detail = S->getStmtClassName();
200 auto SLoc =
Loc.getSourceLocation();
202 return llvm::TimeTraceMetadata{std::move(Detail),
""};
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)};
225 ExprEng.resetCurrStackFrameAndBlock();
238 assert(
false &&
"BlockExit location never occur in forward analysis.");
246 ExprEng.processCallExit(Pred);
251 "Assume epsilon has exactly one predecessor by construction");
285 return "Virtual base initialization skipped because "
286 "it has already been handled by the most derived class";
297 if (Blk == &ExitBlk) {
298 assert(ExitBlk.
empty() &&
"EXIT block cannot contain Stmts.");
304 if (std::optional<CFGStmt> LastStmt = LastElement.
getAs<
CFGStmt>()) {
305 RS = dyn_cast<ReturnStmt>(LastStmt->getStmt());
306 }
else if (std::optional<CFGAutomaticObjDtor> AutoDtor =
307 LastElement.
getAs<CFGAutomaticObjDtor>()) {
308 RS = dyn_cast<ReturnStmt>(AutoDtor->getTriggerStmt());
312 ExplodedNodeSet CheckerNodes;
314 ExprEng.runCheckersForBlockEntrance(BE, Pred, CheckerNodes);
317 for (ExplodedNode *P : CheckerNodes) {
318 ExprEng.processEndOfFunction(P, RS);
327 ExplodedNodeSet DstNodes;
328 NodeBuilder Builder(Pred, DstNodes, ExprEng.getBuilderContext());
329 ExprEng.processCFGBlockEntrance(L, BE, Builder, Pred);
332 if (!Builder.hasGeneratedNodes()) {
333 Builder.generateNode(BE, Pred->State, Pred);
336 ExplodedNodeSet CheckerNodes;
337 for (
auto *N : DstNodes) {
338 ExprEng.runCheckersForBlockEntrance(BE, N, CheckerNodes);
345void CoreEngine::HandleBlockEntrance(
const BlockEntrance &L,
350 BlockCounter Counter = WList->getBlockCounter();
351 Counter = BCounterFactory.IncrementCount(Counter, SF, BlockId);
352 setBlockCounter(Counter);
357 ExprEng.processCFGElement(*E, Pred, 0);
359 HandleBlockExit(L.
getBlock(), Pred);
362void CoreEngine::HandleBlockExit(
const CFGBlock * B,
ExplodedNode *Pred) {
366 switch (Term->getStmtClass()) {
368 llvm_unreachable(
"Analysis for this terminator not implemented.");
370 case Stmt::CXXBindTemporaryExprClass:
371 HandleCleanupTemporaryBranch(
376 case Stmt::DeclStmtClass:
380 case Stmt::BinaryOperatorClass:
384 case Stmt::BinaryConditionalOperatorClass:
385 case Stmt::ConditionalOperatorClass:
393 case Stmt::ChooseExprClass:
397 case Stmt::CXXTryStmtClass:
400 for (
const CFGBlock *Succ : B->
succs()) {
403 if (ExplodedNode *N =
makeNode(BE, Pred->State, Pred))
409 case Stmt::DoStmtClass:
410 HandleBranch(
cast<DoStmt>(Term)->getCond(), Term, B, Pred);
413 case Stmt::CXXForRangeStmtClass:
417 case Stmt::ForStmtClass:
421 case Stmt::SEHLeaveStmtClass:
422 case Stmt::ContinueStmtClass:
423 case Stmt::BreakStmtClass:
424 case Stmt::GotoStmtClass:
427 case Stmt::IfStmtClass:
428 HandleBranch(
cast<IfStmt>(Term)->getCond(), Term, B, Pred);
431 case Stmt::IndirectGotoStmtClass: {
435 ExprEng.processIndirectGoto(Dst,
442 case Stmt::ObjCForCollectionStmtClass:
453 HandleBranch(Term, Term, B, Pred);
456 case Stmt::SwitchStmtClass: {
464 case Stmt::WhileStmtClass:
468 case Stmt::GCCAsmStmtClass:
469 assert(
cast<GCCAsmStmt>(Term)->isAsmGoto() &&
"Encountered GCCAsmStmt without labels");
476 HandleVirtualBaseBranch(B, Pred);
481 "Blocks with no terminator should have at most 1 successor.");
484 if (ExplodedNode *N =
makeNode(BE, Pred->State, Pred))
488void CoreEngine::HandleCallEnter(
const CallEnter &CE,
ExplodedNode *Pred) {
490 ExprEng.processCallEnter(CE, Pred);
493void CoreEngine::HandleBranch(
const Stmt *
Cond,
const Stmt *Term,
499 getCompletedIterationCount(B, Pred));
504void CoreEngine::HandleCleanupTemporaryBranch(
const CXXBindTemporaryExpr *BTE,
509 ExprEng.processCleanupTemporaryBranch(BTE, Pred, Dst, *(B->
succ_begin()),
515void CoreEngine::HandleStaticInit(
const DeclStmt *DS,
const CFGBlock *B,
519 ExprEng.processStaticInitializer(DS, Pred, Dst, *(B->
succ_begin()),
525void CoreEngine::HandlePostStmt(
const CFGBlock *B,
unsigned StmtIdx,
531 while (StmtIdx < B->size() &&
536 if (StmtIdx == B->
size())
537 HandleBlockExit(B, Pred);
540 ExprEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx);
544void CoreEngine::HandleVirtualBaseBranch(
const CFGBlock *B,
547 if (
const auto *CallerCtor =
548 dyn_cast_or_null<CXXConstructExpr>(SF->
getCallSite())) {
549 switch (CallerCtor->getConstructionKind()) {
553 HandleBlockEdge(Loc, Pred);
564 HandleBlockEdge(Loc, Pred);
569 bool MarkAsSink)
const {
570 MarkAsSink = MarkAsSink || State->isPosteriorlyOverconstrained();
576 return IsNew ? N :
nullptr;
588 WList->enqueue(N,
Block, Idx);
596 WList->enqueue(N,
Block, Idx+1);
601 WList->enqueue(N,
Block, Idx);
606 WList->enqueue(N,
Block, Idx+1);
617 WList->enqueue(N,
Block, Idx+1);
624 WList->enqueue(Succ,
Block, Idx+1);
627std::optional<unsigned>
628CoreEngine::getCompletedIterationCount(
const CFGBlock *B,
636 assert(BlockCount >= 1 &&
637 "Block count of currently analyzed block must be >= 1");
638 return BlockCount - 1;
651 for (
const auto I :
Set)
657 for (
const auto I :
Set)
670 WList->enqueue(Succ);
673 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.
Represents a point when we exit a loop.
Represents a program point just after an implicit call event.
static StringRef getProgramPointKindName(Kind K)
ProgramPoint withTag(const ProgramPointTag *tag) const
Create a new ProgramPoint object that is the same as the original except for using the specified tag ...
const StackFrame * getStackFrame() const
std::optional< T > getAs() const
Convert to the specified ProgramPoint type, returning std::nullopt if this ProgramPoint is not of the...
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
It represents a stack frame of the call stack.
LLVM_ATTRIBUTE_RETURNS_NONNULL AnalysisDeclContext * getAnalysisDeclContext() const
const Expr * getCallSite() const
const Decl * getDecl() const
const StackFrame * getParent() const
It might return null.
Stmt - This represents one statement.
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 StackFrame *SF, unsigned Steps, ProgramStateRef InitState)
ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
void enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS)
enqueue the nodes corresponding to the end of function onto the end of path / work list.
ExplodedNode * makeNode(const ProgramPoint &Loc, ProgramStateRef State, ExplodedNode *Pred, bool MarkAsSink=false) const
void enqueue(ExplodedNodeSet &Set)
Enqueue the given set of nodes onto the work list.
ExplodedNodeSet is a set of ExplodedNode * elements with the invariant that its elements cannot be nu...
const ProgramStateRef & getState() const
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
void addPredecessor(ExplodedNode *V, ExplodedGraph &G)
addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...
bool hasSinglePred() const
ExplodedNode * getFirstPred()
const StackFrame * getStackFrame() const
void setCurrStackFrameAndBlock(const StackFrame *SF, 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