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);
700 const CFGBlock *Dst = Branch ? DstT : DstF;
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.
succ_reverse_iterator succ_rend()
succ_reverse_iterator succ_rbegin()
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.
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;.
const Stmt * 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 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()
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 * 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.
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