29#include "llvm/ADT/STLExtras.h"
30#include "llvm/ADT/Statistic.h"
31#include "llvm/Support/Casting.h"
32#include "llvm/Support/ErrorHandling.h"
42#define DEBUG_TYPE "CoreEngine"
45 "The # of steps executed.");
46STATISTIC(NumSTUSteps,
"The # of STU steps executed.");
47STATISTIC(NumCTUSteps,
"The # of CTU steps executed.");
49 "The # of times we reached the max number of steps.");
51 "The # of paths explored by the analyzer.");
59 case ExplorationStrategyKind::DFS:
61 case ExplorationStrategyKind::BFS:
63 case ExplorationStrategyKind::BFSBlockDFSContents:
65 case ExplorationStrategyKind::UnexploredFirst:
67 case ExplorationStrategyKind::UnexploredFirstQueue:
69 case ExplorationStrategyKind::UnexploredFirstLocationQueue:
72 llvm_unreachable(
"Unknown AnalyzerOptions::ExplorationStrategyKind");
79 BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {}
82 WList->setBlockCounter(
C);
84 CTUWList->setBlockCounter(
C);
95 assert(Entry->
empty() &&
"Entry block must be empty.");
97 assert(Entry->
succ_size() == 1 &&
"Entry block must have 1 successor.");
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 =
171 unsigned MaxCTUSteps = std::max(STUSteps * Pct / 100, MinCTUSteps);
173 WList = std::move(CTUWList);
174 const unsigned CTUSteps = ProcessWList(MaxCTUSteps);
175 NumCTUSteps += CTUSteps;
179 return WList->hasWork();
185 switch (
Loc.getKind()) {
195 assert(
false &&
"BlockExit location never occur in forward analysis.");
208 "Assume epsilon has exactly one predecessor by construction");
255 return "Virtual base initialization skipped because "
256 "it has already been handled by the most derived class";
262 Pred = Bldr.generateNode(
P, Pred->
getState(), Pred);
270 "EXIT block cannot contain Stmts.");
276 if (std::optional<CFGStmt> LastStmt = LastElement.
getAs<
CFGStmt>()) {
277 RS = dyn_cast<ReturnStmt>(LastStmt->getStmt());
278 }
else if (std::optional<CFGAutomaticObjDtor> AutoDtor =
280 RS = dyn_cast<ReturnStmt>(AutoDtor->getTriggerStmt());
298 if (!nodeBuilder.hasGeneratedNodes()) {
299 nodeBuilder.generateNode(Pred->State, Pred);
314 setBlockCounter(Counter);
321 HandleBlockExit(L.
getBlock(), Pred);
326 switch (Term->getStmtClass()) {
328 llvm_unreachable(
"Analysis for this terminator not implemented.");
330 case Stmt::CXXBindTemporaryExprClass:
331 HandleCleanupTemporaryBranch(
332 cast<CXXBindTemporaryExpr>(Term), B, Pred);
336 case Stmt::DeclStmtClass:
337 HandleStaticInit(cast<DeclStmt>(Term), B, Pred);
340 case Stmt::BinaryOperatorClass:
341 HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
344 case Stmt::BinaryConditionalOperatorClass:
345 case Stmt::ConditionalOperatorClass:
346 HandleBranch(cast<AbstractConditionalOperator>(Term)->getCond(),
353 case Stmt::ChooseExprClass:
354 HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
357 case Stmt::CXXTryStmtClass:
361 et = B->
succ_end(); it != et; ++it) {
369 case Stmt::DoStmtClass:
370 HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
373 case Stmt::CXXForRangeStmtClass:
374 HandleBranch(cast<CXXForRangeStmt>(Term)->getCond(), Term, B, Pred);
377 case Stmt::ForStmtClass:
378 HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
381 case Stmt::SEHLeaveStmtClass:
382 case Stmt::ContinueStmtClass:
383 case Stmt::BreakStmtClass:
384 case Stmt::GotoStmtClass:
387 case Stmt::IfStmtClass:
388 HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
391 case Stmt::IndirectGotoStmtClass: {
396 builder(Pred, B, cast<IndirectGotoStmt>(Term)->getTarget(),
403 case Stmt::ObjCForCollectionStmtClass:
414 HandleBranch(Term, Term, B, Pred);
417 case Stmt::SwitchStmtClass: {
425 case Stmt::WhileStmtClass:
426 HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
429 case Stmt::GCCAsmStmtClass:
430 assert(cast<GCCAsmStmt>(Term)->isAsmGoto() &&
"Encountered GCCAsmStmt without labels");
437 HandleVirtualBaseBranch(B, Pred);
442 "Blocks with no terminator should have at most 1 successor.");
453void CoreEngine::HandleBranch(
const Stmt *Cond,
const Stmt *Term,
487void CoreEngine::HandlePostStmt(
const CFGBlock *B,
unsigned StmtIdx,
492 if (StmtIdx == B->
size())
493 HandleBlockExit(B, Pred);
500void CoreEngine::HandleVirtualBaseBranch(
const CFGBlock *B,
503 if (
const auto *CallerCtor = dyn_cast_or_null<CXXConstructExpr>(
505 switch (CallerCtor->getConstructionKind()) {
509 HandleBlockEdge(
Loc, Pred);
520 HandleBlockEdge(
Loc, Pred);
532 Node->addPredecessor(Pred, G);
539 if (IsNew) WList->enqueue(
Node);
551 WList->enqueue(N,
Block, Idx);
559 WList->enqueue(N,
Block, Idx+1);
564 WList->enqueue(N,
Block, Idx);
569 WList->enqueue(N,
Block, Idx+1);
580 WList->enqueue(N,
Block, Idx+1);
589 WList->enqueue(Succ,
Block, Idx+1);
602 Node->addPredecessor(N, G);
603 return isNew ?
Node :
nullptr;
607 for (
const auto I : Set)
613 for (
const auto I : Set)
618 for (
auto *I : Set) {
620 if (I->getLocationContext()->getParent()) {
621 I = generateCallExitBeginNode(I, RS);
632void NodeBuilder::anchor() {}
653void NodeBuilderWithSinks::anchor() {}
661void BranchNodeBuilder::anchor() {}
690 Eng.WList->enqueue(Succ);
706 Eng.WList->enqueue(Succ);
732 Eng.WList->enqueue(Succ);
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static std::unique_ptr< WorkList > generateWorkList(AnalyzerOptions &Opts)
STATISTIC(NumSteps, "The # of steps executed.")
static Decl::Kind getKind(const Decl *D)
Defines the clang::Expr interface and subclasses for C++ expressions.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
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...
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
AdjacentBlocks::const_iterator const_succ_iterator
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 binding an expression to a temporary.
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).
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
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
const StackFrameContext * getStackFrame() const
Represents a point when we exit a loop.
Represents a program point just after an implicit call event.
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.
AnalyzerOptions & options
BlockCounter IncrementCount(BlockCounter BC, const StackFrameContext *CallSite, unsigned BlockID)
BlockCounter GetEmptyCounter()
An abstract data type used to count the number of times a given block has been visited along a path a...
ExplodedNode * generateNode(ProgramStateRef State, bool branch, ExplodedNode *Pred)
bool isFeasible(bool branch)
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.
bool ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps, ProgramStateRef InitState, ExplodedNodeSet &Dst)
Returns true if there is still simulation state on the worklist.
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.
void enqueue(ExplodedNodeSet &Set)
Enqueue the given set of nodes onto the work list.
ExplodedNode * addRoot(ExplodedNode *V)
addRoot - Add an untyped node to the set of roots.
void reserve(unsigned NodeCount)
NodeVector::iterator eop_iterator
unsigned num_roots() const
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 * 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 ...
bool hasSinglePred() const
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.
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 processBranch(const Stmt *Condition, NodeBuilderContext &BuilderCtx, ExplodedNode *Pred, ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF)
ProcessBranch - Called by CoreEngine.
void processCFGElement(const CFGElement E, ExplodedNode *Pred, unsigned StmtIdx, NodeBuilderContext *Ctx)
processCFGElement - Called by CoreEngine.
void processStaticInitializer(const DeclStmt *DS, NodeBuilderContext &BuilderCtx, ExplodedNode *Pred, ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF)
Called by CoreEngine.
void processSwitch(SwitchNodeBuilder &builder)
ProcessSwitch - Called by CoreEngine.
void processEndWorklist()
Called by CoreEngine when the analysis worklist has terminated.
void processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE, NodeBuilderContext &BldCtx, ExplodedNode *Pred, ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF)
Called by CoreEngine.
AnalysisManager & getAnalysisManager()
void processIndirectGoto(IndirectGotoNodeBuilder &builder)
processIndirectGoto - Called by CoreEngine.
void markVisitedBasicBlock(unsigned ID, const Decl *D, unsigned TotalIDs)
const CFGBlock * getBlock() const
ExplodedNode * generateNode(const iterator &I, ProgramStateRef State, bool isSink=false)
This node builder keeps track of the generated sink nodes.
This is the simplest builder which generates nodes in the ExplodedGraph.
const NodeBuilderContext & C
ExplodedNodeSet & Frontier
The frontier set - a set of nodes which need to be propagated after the builder dies.
void addNodes(const ExplodedNodeSet &S)
ExplodedNode * generateNodeImpl(const ProgramPoint &PP, ProgramStateRef State, ExplodedNode *Pred, bool MarkAsSink=false)
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.
~StmtNodeBuilder() override
const CFGBlock * getBlock() const
ExplodedNode * generateDefaultCaseNode(ProgramStateRef State, bool isSink=false)
ExplodedNode * generateCaseStmtNode(const iterator &I, ProgramStateRef State)
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()
@ C
Languages that the frontend can parse and compile.