30 #include "llvm/ADT/Optional.h" 31 #include "llvm/ADT/STLExtras.h" 32 #include "llvm/ADT/Statistic.h" 33 #include "llvm/Support/Casting.h" 34 #include "llvm/Support/ErrorHandling.h" 40 using namespace clang;
43 #define DEBUG_TYPE "CoreEngine" 46 "The # of steps executed.");
48 "The # of times we reached the max number of steps.");
50 "The # of paths explored by the analyzer.");
69 llvm_unreachable(
"Unexpected case");
76 BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {}
86 assert(Entry->
empty() &&
"Entry block must be empty.");
88 assert(Entry->
succ_size() == 1 &&
"Entry block must have 1 successor.");
121 bool UnlimitedSteps = Steps == 0;
124 const unsigned PreReservationCap = 4000000;
128 while (WList->hasWork()) {
129 if (!UnlimitedSteps) {
131 NumReachedMaxSteps++;
150 return WList->hasWork();
166 assert(
false &&
"BlockExit location never occur in forward analysis.");
179 "Assume epsilon has exactly one predecessor by construction");
221 "EXIT block cannot contain Stmts.");
227 RS = dyn_cast<
ReturnStmt>(LastStmt->getStmt());
245 if (!nodeBuilder.hasGeneratedNodes()) {
246 nodeBuilder.generateNode(Pred->State, Pred);
261 WList->setBlockCounter(Counter);
269 HandleBlockExit(L.
getBlock(), Pred);
274 switch (Term->getStmtClass()) {
276 llvm_unreachable(
"Analysis for this terminator not implemented.");
278 case Stmt::CXXBindTemporaryExprClass:
279 HandleCleanupTemporaryBranch(
284 case Stmt::DeclStmtClass:
285 HandleStaticInit(cast<DeclStmt>(Term), B, Pred);
288 case Stmt::BinaryOperatorClass:
289 HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
292 case Stmt::BinaryConditionalOperatorClass:
293 case Stmt::ConditionalOperatorClass:
294 HandleBranch(cast<AbstractConditionalOperator>(Term)->getCond(),
301 case Stmt::ChooseExprClass:
302 HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
305 case Stmt::CXXTryStmtClass:
309 et = B->
succ_end(); it != et; ++it) {
317 case Stmt::DoStmtClass:
318 HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
321 case Stmt::CXXForRangeStmtClass:
322 HandleBranch(cast<CXXForRangeStmt>(Term)->getCond(), Term, B, Pred);
325 case Stmt::ForStmtClass:
326 HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
329 case Stmt::ContinueStmtClass:
330 case Stmt::BreakStmtClass:
331 case Stmt::GotoStmtClass:
334 case Stmt::IfStmtClass:
335 HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
338 case Stmt::IndirectGotoStmtClass: {
343 builder(Pred, B, cast<IndirectGotoStmt>(Term)->getTarget(),
350 case Stmt::ObjCForCollectionStmtClass:
361 HandleBranch(Term, Term, B, Pred);
364 case Stmt::SwitchStmtClass: {
372 case Stmt::WhileStmtClass:
373 HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
379 "Blocks with no terminator should have at most 1 successor.");
390 void CoreEngine::HandleBranch(
const Stmt *Cond,
const Stmt *Term,
424 void CoreEngine::HandlePostStmt(
const CFGBlock *B,
unsigned StmtIdx,
429 if (StmtIdx == B->
size())
430 HandleBlockExit(B, Pred);
453 if (IsNew) WList->enqueue(Node);
457 const CFGBlock *Block,
unsigned Idx) {
465 WList->enqueue(N, Block, Idx);
473 WList->enqueue(N, Block, Idx+1);
478 WList->enqueue(N, Block, Idx);
483 WList->enqueue(N, Block, Idx+1);
494 WList->enqueue(N, Block, Idx+1);
503 WList->enqueue(Succ, Block, Idx+1);
517 return isNew ?
Node :
nullptr;
521 for (
const auto I : Set)
526 const CFGBlock *Block,
unsigned Idx) {
527 for (
const auto I : Set)
534 if (I->getLocationContext()->getParent()) {
535 I = generateCallExitBeginNode(I, RS);
546 void NodeBuilder::anchor() {}
552 HasGeneratedNodes =
true;
554 ExplodedNode *N = C.Eng.G.getNode(Loc, State, MarkAsSink, &IsNew);
556 Frontier.erase(FromN);
567 void NodeBuilderWithSinks::anchor() {}
571 for (
const auto I : Frontier)
572 EnclosingBldr->addNodes(I);
575 void BranchNodeBuilder::anchor() {}
581 if (!isFeasible(branch))
586 ExplodedNode *Succ = generateNodeImpl(Loc, State, NodePred);
604 Eng.WList->enqueue(Succ);
620 Eng.WList->enqueue(Succ);
628 assert(Src->succ_rbegin() != Src->succ_rend());
646 Eng.WList->enqueue(Succ);
succ_reverse_iterator succ_rbegin()
const Stmt * getStmt() const
succ_iterator succ_begin()
bool ExecuteWorkList(const LocationContext *L, unsigned Steps, ProgramStateRef InitState)
ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
Stmt - This represents one statement.
unsigned getBlockID() const
const CFGBlock * getSrc() const
Represents a point when we begin processing an inlined call.
ProgramPoint withTag(const ProgramPointTag *tag) const
Create a new ProgramPoint object that is the same as the original except for using the specified tag ...
virtual ProgramStateRef getInitialState(const LocationContext *InitLoc)=0
STATISTIC(NumSteps, "The # of steps executed.")
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type...
~StmtNodeBuilder() override
const ProgramStateRef & getState() const
An abstract data type used to count the number of times a given block has been visited along a path a...
static std::unique_ptr< WorkList > makeUnexploredFirstPriorityQueue()
Optional< CFGElement > getFirstElement() const
Represents a point when we exit a loop.
unsigned succ_size() const
virtual void processCFGElement(const CFGElement E, ExplodedNode *Pred, unsigned StmtIdx, NodeBuilderContext *Ctx)=0
Called by CoreEngine.
void enqueue(ExplodedNodeSet &Set)
Enqueue the given set of nodes onto the work list.
bool ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps, ProgramStateRef InitState, ExplodedNodeSet &Dst)
Returns true if there is still simulation state on the worklist.
Defines the clang::Expr interface and subclasses for C++ expressions.
const CFGBlock * getEntry() const
Returns the entry block in the CFG for the entered function.
bool hasWorkRemaining() const
static std::unique_ptr< WorkList > makeDFS()
CoreEngine(SubEngine &subengine, FunctionSummariesTy *FS, AnalyzerOptions &Opts)
Construct a CoreEngine object to analyze the provided CFG.
bool hasSinglePred() const
void addPredecessor(ExplodedNode *V, ExplodedGraph &G)
addPredeccessor - Adds a predecessor to the current node, and in tandem add this node as a successor ...
Represents a point when we start the call exit sequence (for inlined call).
AdjacentBlocks::const_iterator const_succ_iterator
This is a meta program point, which should be skipped by all the diagnostic reasoning etc...
ExplodedNode * generateNodeImpl(const ProgramPoint &PP, ProgramStateRef State, ExplodedNode *Pred, bool MarkAsSink=false)
virtual void processIndirectGoto(IndirectGotoNodeBuilder &builder)=0
Called by CoreEngine.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
const LocationContext * getLocationContext() const
ExplodedNode * generateCaseStmtNode(const iterator &I, ProgramStateRef State)
const CFGBlock * getBlock() const
BlockCounter getBlockCounter() const
Returns the block counter map associated with the worklist unit.
virtual void processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE, NodeBuilderContext &BldCtx, ExplodedNode *Pred, ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF)=0
Called by CoreEngine.
Represents binding an expression to a temporary.
ExplodedNode * getFirstPred()
static std::unique_ptr< WorkList > makeBFS()
Represents a single basic block in a source-level CFG.
virtual void processBranch(const Stmt *Condition, const Stmt *Term, NodeBuilderContext &BuilderCtx, ExplodedNode *Pred, ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF)=0
Called by CoreEngine.
Represents a point when we finish the call exit sequence (for inlined call).
const CFGBlock * getBlock() const
virtual void processSwitch(SwitchNodeBuilder &builder)=0
Called by CoreEngine.
unsigned getIndex() const
Return the index within the CFGBlock for the worklist unit.
void Add(ExplodedNode *N)
unsigned num_roots() const
const CFGBlock * getDst() const
void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx)
Enqueue a single node created as a result of statement processing.
virtual void processStaticInitializer(const DeclStmt *DS, NodeBuilderContext &BuilderCtx, ExplodedNode *Pred, ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF)=0
Called by CoreEngine.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
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 * getNode() const
Returns the node associated with the worklist unit.
ExplodedNode * generateNode(const iterator &I, ProgramStateRef State, bool isSink=false)
CFGTerminator getTerminator()
T castAs() const
Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type...
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
void dispatchWorkItem(ExplodedNode *Pred, ProgramPoint Loc, const WorkListUnit &WU)
Dispatch the work list item based on the given location information.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
NodeVector::iterator eop_iterator
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
static std::unique_ptr< WorkList > makeBFSBlockDFSContents()
virtual void processCallExit(ExplodedNode *Pred)=0
virtual void processEndWorklist(bool hasWorkRemaining)=0
Called by CoreEngine when the analysis worklist is either empty or the.
Optional< T > getAs() const
Convert to the specified CFGElement type, returning None if this CFGElement is not of the desired typ...
ast_type_traits::DynTypedNode Node
Dataflow Directional Tag Classes.
ExplodedNode * generateDefaultCaseNode(ProgramStateRef State, bool isSink=false)
static std::unique_ptr< WorkList > generateWorkList(AnalyzerOptions &Opts)
Represents a program point just after an implicit call event.
This node builder keeps track of the generated sink nodes.
virtual void processCallEnter(NodeBuilderContext &BC, CallEnter CE, ExplodedNode *Pred)=0
const CFGBlock * getBlock() const
Returns the CFGblock associated with the worklist unit.
const Decl * getDecl() const
void reserve(unsigned NodeCount)
BlockCounter GetEmptyCounter()
ExplorationStrategyKind getExplorationStrategy()
const LocationContext * getLocationContext() const
virtual void processBeginOfFunction(NodeBuilderContext &BC, ExplodedNode *Pred, ExplodedNodeSet &Dst, const BlockEdge &L)=0
Called by CoreEngine.
const StackFrameContext * getStackFrame() const
void enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS)
enqueue the nodes corresponding to the end of function onto the end of path / work list...
ExplodedNode * generateNode(ProgramStateRef State, bool branch, ExplodedNode *Pred)
BlockCounter IncrementCount(BlockCounter BC, const StackFrameContext *CallSite, unsigned BlockID)
virtual void processEndOfFunction(NodeBuilderContext &BC, ExplodedNode *Pred, const ReturnStmt *RS=nullptr)=0
Called by CoreEngine.
ExplodedNode * addEndOfPath(ExplodedNode *V)
addEndOfPath - Add an untyped node to the set of EOP nodes.
static Decl::Kind getKind(const Decl *D)
static std::unique_ptr< WorkList > makeUnexploredFirst()
const CFGBlock * getBlock() const
virtual void processCFGBlockEntrance(const BlockEdge &L, NodeBuilderWithSinks &nodeBuilder, ExplodedNode *Pred)=0
Called by CoreEngine when it starts processing a CFGBlock.
__DEVICE__ int min(int __a, int __b)
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
ExplodedNode * addRoot(ExplodedNode *V)
addRoot - Add an untyped node to the set of roots.
void markVisitedBasicBlock(unsigned ID, const Decl *D, unsigned TotalIDs)