21 #include "llvm/ADT/Statistic.h"
22 #include "llvm/Support/Casting.h"
24 using namespace clang;
27 #define DEBUG_TYPE "CoreEngine"
30 "The # of steps executed.");
32 "The # of times we reached the max number of steps.");
34 "The # of paths explored by the analyzer.");
47 return !
Stack.empty();
55 assert (!
Stack.empty());
72 std::deque<WorkListUnit> Queue;
75 return !Queue.empty();
89 for (std::deque<WorkListUnit>::iterator
90 I = Queue.begin(),
E = Queue.end();
I !=
E; ++
I) {
108 class BFSBlockDFSContents :
public WorkList {
109 std::deque<WorkListUnit> Queue;
112 bool hasWork()
const override {
113 return !Queue.empty() || !
Stack.empty();
125 if (!
Stack.empty()) {
131 assert(!Queue.empty());
144 for (std::deque<WorkListUnit>::iterator
145 I = Queue.begin(),
E = Queue.end();
I !=
E; ++
I) {
156 return new BFSBlockDFSContents();
167 if (G.num_roots() == 0) {
172 assert (Entry->
empty() &&
173 "Entry block must be empty.");
176 "Entry block must have 1 successor.");
179 FunctionSummaries->markVisitedBasicBlock(Entry->
getBlockID(),
191 WList->setBlockCounter(BCounterFactory.GetEmptyCounter());
194 InitState = SubEng.getInitialState(L);
203 SubEng.processBeginOfFunction(BuilderCtx, Node, DstBegin, StartLoc);
209 bool UnlimitedSteps = Steps == 0;
212 const unsigned PreReservationCap = 4000000;
214 G.reserve(
std::min(Steps,PreReservationCap));
216 while (WList->hasWork()) {
217 if (!UnlimitedSteps) {
219 NumReachedMaxSteps++;
237 SubEng.processEndWorklist(hasWorkRemaining());
238 return WList->hasWork();
254 assert (
false &&
"BlockExit location never occur in forward analysis.");
263 SubEng.processCallExit(Pred);
268 "Assume epsilon has exactly one predecessor by construction");
287 bool DidNotFinish = ExecuteWorkList(L, Steps, InitState);
302 FunctionSummaries->markVisitedBasicBlock(Blk->
getBlockID(),
310 &&
"EXIT block cannot contain Stmts.");
316 if ((RS = dyn_cast<ReturnStmt>(LastStmt->getStmt()))) {
317 if (!RS->getRetValue())
324 SubEng.processEndOfFunction(BuilderCtx, Pred, RS);
334 SubEng.processCFGBlockEntrance(L, nodeBuilder, Pred);
337 if (!nodeBuilder.hasGeneratedNodes()) {
338 nodeBuilder.generateNode(Pred->State, Pred);
354 WList->setBlockCounter(Counter);
359 SubEng.processCFGElement(*
E, Pred, 0, &Ctx);
362 HandleBlockExit(L.
getBlock(), Pred);
368 switch (Term->getStmtClass()) {
370 llvm_unreachable(
"Analysis for this terminator not implemented.");
372 case Stmt::CXXBindTemporaryExprClass:
373 HandleCleanupTemporaryBranch(
378 case Stmt::DeclStmtClass:
379 HandleStaticInit(cast<DeclStmt>(Term), B, Pred);
382 case Stmt::BinaryOperatorClass:
383 HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
386 case Stmt::BinaryConditionalOperatorClass:
387 case Stmt::ConditionalOperatorClass:
388 HandleBranch(cast<AbstractConditionalOperator>(Term)->getCond(),
395 case Stmt::ChooseExprClass:
396 HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
399 case Stmt::CXXTryStmtClass: {
403 et = B->
succ_end(); it != et; ++it) {
412 case Stmt::DoStmtClass:
413 HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
416 case Stmt::CXXForRangeStmtClass:
417 HandleBranch(cast<CXXForRangeStmt>(Term)->getCond(), Term, B, Pred);
420 case Stmt::ForStmtClass:
421 HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
424 case Stmt::ContinueStmtClass:
425 case Stmt::BreakStmtClass:
426 case Stmt::GotoStmtClass:
429 case Stmt::IfStmtClass:
430 HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
433 case Stmt::IndirectGotoStmtClass: {
438 builder(Pred, B, cast<IndirectGotoStmt>(Term)->getTarget(),
441 SubEng.processIndirectGoto(builder);
445 case Stmt::ObjCForCollectionStmtClass: {
456 HandleBranch(Term, Term, B, Pred);
460 case Stmt::SwitchStmtClass: {
464 SubEng.processSwitch(builder);
468 case Stmt::WhileStmtClass:
469 HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
475 "Blocks with no terminator should have at most 1 successor.");
483 SubEng.processCallEnter(BuilderCtx, CE, Pred);
486 void CoreEngine::HandleBranch(
const Stmt *Cond,
const Stmt *Term,
491 SubEng.processBranch(Cond, Term, Ctx, Pred, Dst,
503 SubEng.processCleanupTemporaryBranch(BTE, Ctx, Pred, Dst, *(B->
succ_begin()),
514 SubEng.processStaticInitializer(DS, Ctx, Pred, Dst,
521 void CoreEngine::HandlePostStmt(
const CFGBlock *B,
unsigned StmtIdx,
526 if (StmtIdx == B->
size())
527 HandleBlockExit(B, Pred);
530 SubEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx);
551 if (IsNew) WList->enqueue(Node);
555 const CFGBlock *Block,
unsigned Idx) {
563 WList->enqueue(N, Block, Idx);
570 WList->enqueue(N, Block, Idx+1);
575 WList->enqueue(N, Block, Idx);
580 WList->enqueue(N, Block, Idx+1);
591 WList->enqueue(N, Block, Idx+1);
600 WList->enqueue(Succ, Block, Idx+1);
615 return isNew ? Node :
nullptr;
627 const CFGBlock *Block,
unsigned Idx) {
630 enqueueStmtNode(*
I, Block, Idx);
639 N = generateCallExitBeginNode(N, RS);
651 void NodeBuilder::anchor() { }
657 HasGeneratedNodes =
true;
659 ExplodedNode *N = C.Eng.G.getNode(Loc, State, MarkAsSink, &IsNew);
661 Frontier.erase(FromN);
672 void NodeBuilderWithSinks::anchor() { }
677 E = Frontier.end();
I !=
E; ++
I )
678 EnclosingBldr->addNodes(*
I);
681 void BranchNodeBuilder::anchor() { }
687 if (!isFeasible(branch))
692 ExplodedNode *Succ = generateNodeImpl(Loc, State, NodePred);
710 Eng.WList->enqueue(Succ);
728 Eng.WList->enqueue(Succ);
737 assert(Src->succ_rbegin() != Src->succ_rend());
755 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.
Stmt - This represents one statement.
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 * getSrc() 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
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
ExplodedNode * generateNode(const iterator &I, ProgramStateRef State, bool isSink=false)
unsigned getIndex() const
Return the index within the CFGBlock for the worklist unit.
CFGTerminator getTerminator()
ExplodedNode * getNode() const
Returns the node associated with the worklist unit.
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
void enqueueEndOfFunction(ExplodedNodeSet &Set, const ReturnStmt *RS)
enqueue the nodes corresponding to the end of function onto the end of path / work list...
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()
Optional< T > getAs() const
Convert to the specified CFGElement type, returning None if this CFGElement is not of the desired typ...