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());
63 I = Stack.begin(), E = Stack.end(); I != E; ++I) {
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());
140 I = Stack.begin(), E = Stack.end(); I != E; ++I) {
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");
288 bool DidNotFinish = ExecuteWorkList(L, Steps, InitState);
303 FunctionSummaries->markVisitedBasicBlock(Blk->
getBlockID(),
311 &&
"EXIT block cannot contain Stmts.");
317 if ((RS = dyn_cast<ReturnStmt>(LastStmt->getStmt()))) {
318 if (!RS->getRetValue())
325 SubEng.processEndOfFunction(BuilderCtx, Pred, RS);
335 SubEng.processCFGBlockEntrance(L, nodeBuilder, Pred);
338 if (!nodeBuilder.hasGeneratedNodes()) {
339 nodeBuilder.generateNode(Pred->State, Pred);
355 WList->setBlockCounter(Counter);
360 SubEng.processCFGElement(*E, Pred, 0, &Ctx);
363 HandleBlockExit(L.
getBlock(), Pred);
369 switch (Term->getStmtClass()) {
371 llvm_unreachable(
"Analysis for this terminator not implemented.");
373 case Stmt::CXXBindTemporaryExprClass:
374 HandleCleanupTemporaryBranch(
379 case Stmt::DeclStmtClass:
380 HandleStaticInit(cast<DeclStmt>(Term), B, Pred);
383 case Stmt::BinaryOperatorClass:
384 HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
387 case Stmt::BinaryConditionalOperatorClass:
388 case Stmt::ConditionalOperatorClass:
389 HandleBranch(cast<AbstractConditionalOperator>(Term)->getCond(),
396 case Stmt::ChooseExprClass:
397 HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
400 case Stmt::CXXTryStmtClass: {
404 et = B->
succ_end(); it != et; ++it) {
413 case Stmt::DoStmtClass:
414 HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
417 case Stmt::CXXForRangeStmtClass:
418 HandleBranch(cast<CXXForRangeStmt>(Term)->getCond(), Term, B, Pred);
421 case Stmt::ForStmtClass:
422 HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
425 case Stmt::ContinueStmtClass:
426 case Stmt::BreakStmtClass:
427 case Stmt::GotoStmtClass:
430 case Stmt::IfStmtClass:
431 HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
434 case Stmt::IndirectGotoStmtClass: {
439 builder(Pred, B, cast<IndirectGotoStmt>(Term)->getTarget(),
442 SubEng.processIndirectGoto(builder);
446 case Stmt::ObjCForCollectionStmtClass: {
457 HandleBranch(Term, Term, B, Pred);
461 case Stmt::SwitchStmtClass: {
465 SubEng.processSwitch(builder);
469 case Stmt::WhileStmtClass:
470 HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
476 "Blocks with no terminator should have at most 1 successor.");
484 SubEng.processCallEnter(BuilderCtx, CE, Pred);
487 void CoreEngine::HandleBranch(
const Stmt *Cond,
const Stmt *Term,
492 SubEng.processBranch(Cond, Term, Ctx, Pred, Dst,
504 SubEng.processCleanupTemporaryBranch(BTE, Ctx, Pred, Dst, *(B->
succ_begin()),
515 SubEng.processStaticInitializer(DS, Ctx, Pred, Dst,
522 void CoreEngine::HandlePostStmt(
const CFGBlock *B,
unsigned StmtIdx,
527 if (StmtIdx == B->
size())
528 HandleBlockExit(B, Pred);
531 SubEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx);
552 if (IsNew) WList->enqueue(Node);
556 const CFGBlock *Block,
unsigned Idx) {
564 WList->enqueue(N, Block, Idx);
572 WList->enqueue(N, Block, Idx+1);
577 WList->enqueue(N, Block, Idx);
582 WList->enqueue(N, Block, Idx+1);
593 WList->enqueue(N, Block, Idx+1);
602 WList->enqueue(Succ, Block, Idx+1);
617 return isNew ?
Node :
nullptr;
623 E = Set.
end(); I != E; ++I) {
629 const CFGBlock *Block,
unsigned Idx) {
631 E = Set.
end(); I != E; ++I) {
632 enqueueStmtNode(*I, Block, Idx);
641 N = generateCallExitBeginNode(N, RS);
653 void NodeBuilder::anchor() { }
659 HasGeneratedNodes =
true;
661 ExplodedNode *N = C.Eng.G.getNode(Loc, State, MarkAsSink, &IsNew);
663 Frontier.erase(FromN);
674 void NodeBuilderWithSinks::anchor() { }
679 E = Frontier.end(); I != E; ++I )
680 EnclosingBldr->addNodes(*I);
683 void BranchNodeBuilder::anchor() { }
689 if (!isFeasible(branch))
694 ExplodedNode *Succ = generateNodeImpl(Loc, State, NodePred);
712 Eng.WList->enqueue(Succ);
730 Eng.WList->enqueue(Succ);
739 assert(Src->succ_rbegin() != Src->succ_rend());
757 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 ...
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...
Optional< CFGElement > getFirstElement() const
Represents a point when we exit a loop.
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.
const CFGBlock * getEntry() const
Returns the entry block in the CFG for the entered function.
ImplTy::iterator iterator
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)
const StackFrameContext * getCurrentStackFrame() const
const LocationContext * getLocationContext() const
ExplodedNode * generateCaseStmtNode(const iterator &I, ProgramStateRef State)
const CFGBlock * getBlock() const
const LocationContext * getParent() const
BlockCounter getBlockCounter() const
Returns the block counter map associated with the worklist unit.
Represents binding an expression to a temporary.
ExplodedNode * getFirstPred()
CFGBlock - Represents a single basic block in a source-level CFG.
Represents a point when we finish the call exit sequence (for inlined call).
const CFGBlock * getBlock() const
unsigned getIndex() const
Return the index within the CFGBlock for the worklist unit.
void Add(ExplodedNode *N)
char __ovld __cnfn min(char x, char y)
Returns y if y < x, otherwise it returns x.
const CFGBlock * getDst() const
void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx)
Enqueue a single node created as a result of statement processing.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
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...
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.
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
unsigned getNumBlockIDs() const
getNumBlockIDs - Returns the total number of BlockIDs allocated (which start at 0).
virtual WorkListUnit dequeue()=0
static WorkList * makeDFS()
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)
Represents a program point just after an implicit call event.
virtual bool visitItemsInWorkList(Visitor &V)=0
This node builder keeps track of the generated sink nodes.
static WorkList * makeBFSBlockDFSContents()
const CFGBlock * getBlock() const
Returns the CFGblock associated with the worklist unit.
const Decl * getDecl() const
const LocationContext * getLocationContext() const
NodeVector::iterator eop_iterator
virtual bool visit(const WorkListUnit &U)=0
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)
static Decl::Kind getKind(const Decl *D)
virtual void enqueue(const WorkListUnit &U)=0
const CFGBlock * getBlock() const
Optional< T > getAs() const
Convert to the specified ProgramPoint type, returning None if this ProgramPoint is not of the desired...
static WorkList * makeBFS()