21 #include "llvm/ADT/DenseMap.h"
22 #include "llvm/ADT/Statistic.h"
23 #include "llvm/Support/Casting.h"
25 using namespace clang;
28 #define DEBUG_TYPE "CoreEngine"
31 "The # of steps executed.");
33 "The # of times we reached the max number of steps.");
35 "The # of paths explored by the analyzer.");
48 return !
Stack.empty();
56 assert (!
Stack.empty());
73 std::deque<WorkListUnit> Queue;
76 return !Queue.empty();
91 I = Queue.begin(),
E = Queue.end();
I !=
E; ++
I) {
109 class BFSBlockDFSContents :
public WorkList {
110 std::deque<WorkListUnit> Queue;
113 bool hasWork()
const override {
114 return !Queue.empty() || !
Stack.empty();
126 if (!
Stack.empty()) {
132 assert(!Queue.empty());
146 I = Queue.begin(),
E = Queue.end();
I !=
E; ++
I) {
157 return new BFSBlockDFSContents();
168 if (G.num_roots() == 0) {
173 assert (Entry->
empty() &&
174 "Entry block must be empty.");
177 "Entry block must have 1 successor.");
180 FunctionSummaries->markVisitedBasicBlock(Entry->
getBlockID(),
192 WList->setBlockCounter(BCounterFactory.GetEmptyCounter());
195 InitState = SubEng.getInitialState(L);
204 SubEng.processBeginOfFunction(BuilderCtx, Node, DstBegin, StartLoc);
210 bool UnlimitedSteps = Steps == 0;
213 const unsigned PreReservationCap = 4000000;
215 G.reserve(
std::min(Steps,PreReservationCap));
217 while (WList->hasWork()) {
218 if (!UnlimitedSteps) {
220 NumReachedMaxSteps++;
238 SubEng.processEndWorklist(hasWorkRemaining());
239 return WList->hasWork();
255 assert (
false &&
"BlockExit location never occur in forward analysis.");
264 SubEng.processCallExit(Pred);
269 "Assume epsilon has exactly one predecessor by construction");
288 bool DidNotFinish = ExecuteWorkList(L, Steps, InitState);
303 FunctionSummaries->markVisitedBasicBlock(Blk->
getBlockID(),
311 &&
"EXIT block cannot contain Stmts.");
314 SubEng.processEndOfFunction(BuilderCtx, Pred);
324 SubEng.processCFGBlockEntrance(L, nodeBuilder, Pred);
327 if (!nodeBuilder.hasGeneratedNodes()) {
328 nodeBuilder.generateNode(Pred->State, Pred);
344 WList->setBlockCounter(Counter);
349 SubEng.processCFGElement(*
E, Pred, 0, &Ctx);
352 HandleBlockExit(L.
getBlock(), Pred);
358 switch (Term->getStmtClass()) {
360 llvm_unreachable(
"Analysis for this terminator not implemented.");
362 case Stmt::CXXBindTemporaryExprClass:
363 HandleCleanupTemporaryBranch(
368 case Stmt::DeclStmtClass:
369 HandleStaticInit(cast<DeclStmt>(Term), B, Pred);
372 case Stmt::BinaryOperatorClass:
373 HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
376 case Stmt::BinaryConditionalOperatorClass:
377 case Stmt::ConditionalOperatorClass:
378 HandleBranch(cast<AbstractConditionalOperator>(Term)->getCond(),
385 case Stmt::ChooseExprClass:
386 HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
389 case Stmt::CXXTryStmtClass: {
393 et = B->
succ_end(); it != et; ++it) {
402 case Stmt::DoStmtClass:
403 HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
406 case Stmt::CXXForRangeStmtClass:
407 HandleBranch(cast<CXXForRangeStmt>(Term)->getCond(), Term, B, Pred);
410 case Stmt::ForStmtClass:
411 HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
414 case Stmt::ContinueStmtClass:
415 case Stmt::BreakStmtClass:
416 case Stmt::GotoStmtClass:
419 case Stmt::IfStmtClass:
420 HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
423 case Stmt::IndirectGotoStmtClass: {
428 builder(Pred, B, cast<IndirectGotoStmt>(Term)->getTarget(),
431 SubEng.processIndirectGoto(builder);
435 case Stmt::ObjCForCollectionStmtClass: {
446 HandleBranch(Term, Term, B, Pred);
450 case Stmt::SwitchStmtClass: {
454 SubEng.processSwitch(builder);
458 case Stmt::WhileStmtClass:
459 HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
465 "Blocks with no terminator should have at most 1 successor.");
473 SubEng.processCallEnter(BuilderCtx, CE, Pred);
476 void CoreEngine::HandleBranch(
const Stmt *Cond,
const Stmt *Term,
481 SubEng.processBranch(Cond, Term, Ctx, Pred, Dst,
493 SubEng.processCleanupTemporaryBranch(BTE, Ctx, Pred, Dst, *(B->
succ_begin()),
504 SubEng.processStaticInitializer(DS, Ctx, Pred, Dst,
511 void CoreEngine::HandlePostStmt(
const CFGBlock *B,
unsigned StmtIdx,
516 if (StmtIdx == B->
size())
517 HandleBlockExit(B, Pred);
520 SubEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx);
541 if (IsNew) WList->enqueue(Node);
545 const CFGBlock *Block,
unsigned Idx) {
553 WList->enqueue(N, Block, Idx);
560 WList->enqueue(N, Block, Idx+1);
565 WList->enqueue(N, Block, Idx);
570 WList->enqueue(N, Block, Idx+1);
581 WList->enqueue(N, Block, Idx+1);
590 WList->enqueue(Succ, Block, Idx+1);
604 return isNew ? Node :
nullptr;
616 const CFGBlock *Block,
unsigned Idx) {
619 enqueueStmtNode(*
I, Block, Idx);
628 N = generateCallExitBeginNode(N);
640 void NodeBuilder::anchor() { }
646 HasGeneratedNodes =
true;
648 ExplodedNode *N = C.Eng.G.getNode(Loc, State, MarkAsSink, &IsNew);
650 Frontier.erase(FromN);
661 void NodeBuilderWithSinks::anchor() { }
666 E = Frontier.end();
I !=
E; ++
I )
667 EnclosingBldr->addNodes(*
I);
670 void BranchNodeBuilder::anchor() { }
676 if (!isFeasible(branch))
681 ExplodedNode *Succ = generateNodeImpl(Loc, State, NodePred);
699 Eng.WList->enqueue(Succ);
717 Eng.WList->enqueue(Succ);
726 assert(Src->succ_rbegin() != Src->succ_rend());
744 Eng.WList->enqueue(Succ);
succ_reverse_iterator succ_rbegin()
succ_iterator succ_begin()
bool ExecuteWorkList(const LocationContext *L, unsigned Steps, ProgramStateRef InitState)
ExecuteWorkList - Run the worklist algorithm for a maximum number of steps.
BlockCounter getBlockCounter() const
Returns the block counter map associated with the worklist unit.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
Represents a point when we begin processing an inlined call.
~StmtNodeBuilder() override
An abstract data type used to count the number of times a given block has been visited along a path a...
unsigned succ_size() const
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.
ImplTy::iterator iterator
T castAs() const
Convert to the specified CFGElement type, asserting that this CFGElement is of the desired type...
const CFGBlock * getBlock() 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).
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)
ExplodedNode * generateCaseStmtNode(const iterator &I, ProgramStateRef State)
Represents binding an expression to a temporary.
ExplodedNode * getFirstPred()
detail::InMemoryDirectory::const_iterator I
const LocationContext * getLocationContext() const
const CFGBlock * getBlock() const
Returns the CFGblock associated with the worklist unit.
CFGBlock - Represents a single basic block in a source-level CFG.
std::vector< bool > & Stack
Represents a point when we finish the call exit sequence (for inlined call).
const CFGBlock * getDst() const
STATISTIC(NumSteps,"The # of steps executed.")
const ProgramStateRef & getState() const
const CFGBlock * getEntry() const
Returns the entry block in the CFG for the entered function.
void Add(ExplodedNode *N)
char __ovld __cnfn min(char x, char y)
Returns y if y < x, otherwise it returns x.
void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx)
Enqueue a single node created as a result of statement processing.
T castAs() const
Convert to the specified ProgramPoint type, asserting that this ProgramPoint is of the desired type...
unsigned getBlockID() const
ExplodedNode * generateNode(const iterator &I, ProgramStateRef State, bool isSink=false)
unsigned getIndex() const
Return the index within the CFGBlock for the worklist unit.
void enqueueEndOfFunction(ExplodedNodeSet &Set)
enqueue the nodes corresponding to the end of function onto the end of path / work list...
CFGTerminator getTerminator()
ExplodedNode * getNode() const
Returns the node associated with the worklist unit.
const TemplateArgument * iterator
const StackFrameContext * getCurrentStackFrame() const
Optional< CFGElement > getFirstElement() const
virtual bool hasWork() const =0
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.
const Stmt * getStmt() const
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 Decl * getDecl() const
virtual WorkListUnit dequeue()=0
static WorkList * makeDFS()
AdjacentBlocks::const_iterator const_succ_iterator
ast_type_traits::DynTypedNode Node
const LocationContext * getParent() const
ExplodedNode * generateDefaultCaseNode(ProgramStateRef State, bool isSink=false)
Represents a program point just after an implicit call event.
const LocationContext * getLocationContext() const
virtual bool visitItemsInWorkList(Visitor &V)=0
This node builder keeps track of the generated sink nodes.
static WorkList * makeBFSBlockDFSContents()
detail::InMemoryDirectory::const_iterator E
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
NodeVector::iterator eop_iterator
const CFGBlock * getBlock() const
ExplodedNode * generateNode(ProgramStateRef State, bool branch, ExplodedNode *Pred)
bool hasSinglePred() const
static Decl::Kind getKind(const Decl *D)
virtual void enqueue(const WorkListUnit &U)=0
unsigned getNumBlockIDs() const
getNumBlockIDs - Returns the total number of BlockIDs allocated (which start at 0).
const CFGBlock * getBlock() const
static WorkList * makeBFS()