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());
64 I =
Stack.begin(), E =
Stack.end(); I != E; ++I) {
73 std::deque<WorkListUnit> Queue;
76 return !Queue.empty();
90 for (std::deque<WorkListUnit>::iterator
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());
141 I =
Stack.begin(), E =
Stack.end(); I != E; ++I) {
145 for (std::deque<WorkListUnit>::iterator
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());
196 generateNode(StartLoc, SubEng.getInitialState(L),
nullptr);
198 generateNode(StartLoc, InitState,
nullptr);
202 bool UnlimitedSteps = Steps == 0;
204 while (WList->hasWork()) {
205 if (!UnlimitedSteps) {
207 NumReachedMaxSteps++;
225 SubEng.processEndWorklist(hasWorkRemaining());
226 return WList->hasWork();
242 assert (
false &&
"BlockExit location never occur in forward analysis.");
247 SubEng.processCallEnter(CEnter, Pred);
252 SubEng.processCallExit(Pred);
257 "Assume epsilon has exactly one predecessor by construction");
276 bool DidNotFinish = ExecuteWorkList(L, Steps, InitState);
291 FunctionSummaries->markVisitedBasicBlock(Blk->
getBlockID(),
299 &&
"EXIT block cannot contain Stmts.");
302 SubEng.processEndOfFunction(BuilderCtx, Pred);
312 SubEng.processCFGBlockEntrance(L, nodeBuilder, Pred);
315 if (!nodeBuilder.hasGeneratedNodes()) {
316 nodeBuilder.generateNode(Pred->State, Pred);
332 WList->setBlockCounter(Counter);
337 SubEng.processCFGElement(*E, Pred, 0, &Ctx);
340 HandleBlockExit(L.
getBlock(), Pred);
346 switch (Term->getStmtClass()) {
348 llvm_unreachable(
"Analysis for this terminator not implemented.");
350 case Stmt::CXXBindTemporaryExprClass:
351 HandleCleanupTemporaryBranch(
356 case Stmt::DeclStmtClass:
357 HandleStaticInit(cast<DeclStmt>(Term), B, Pred);
360 case Stmt::BinaryOperatorClass:
361 HandleBranch(cast<BinaryOperator>(Term)->getLHS(), Term, B, Pred);
364 case Stmt::BinaryConditionalOperatorClass:
365 case Stmt::ConditionalOperatorClass:
366 HandleBranch(cast<AbstractConditionalOperator>(Term)->getCond(),
373 case Stmt::ChooseExprClass:
374 HandleBranch(cast<ChooseExpr>(Term)->getCond(), Term, B, Pred);
377 case Stmt::CXXTryStmtClass: {
381 et = B->
succ_end(); it != et; ++it) {
390 case Stmt::DoStmtClass:
391 HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
394 case Stmt::CXXForRangeStmtClass:
395 HandleBranch(cast<CXXForRangeStmt>(Term)->getCond(), Term, B, Pred);
398 case Stmt::ForStmtClass:
399 HandleBranch(cast<ForStmt>(Term)->getCond(), Term, B, Pred);
402 case Stmt::ContinueStmtClass:
403 case Stmt::BreakStmtClass:
404 case Stmt::GotoStmtClass:
407 case Stmt::IfStmtClass:
408 HandleBranch(cast<IfStmt>(Term)->getCond(), Term, B, Pred);
411 case Stmt::IndirectGotoStmtClass: {
416 builder(Pred, B, cast<IndirectGotoStmt>(Term)->getTarget(),
419 SubEng.processIndirectGoto(builder);
423 case Stmt::ObjCForCollectionStmtClass: {
434 HandleBranch(Term, Term, B, Pred);
438 case Stmt::SwitchStmtClass: {
442 SubEng.processSwitch(builder);
446 case Stmt::WhileStmtClass:
447 HandleBranch(cast<WhileStmt>(Term)->getCond(), Term, B, Pred);
453 "Blocks with no terminator should have at most 1 successor.");
459 void CoreEngine::HandleBranch(
const Stmt *Cond,
const Stmt *Term,
464 SubEng.processBranch(Cond, Term, Ctx, Pred, Dst,
476 SubEng.processCleanupTemporaryBranch(BTE, Ctx, Pred, Dst, *(B->
succ_begin()),
487 SubEng.processStaticInitializer(DS, Ctx, Pred, Dst,
494 void CoreEngine::HandlePostStmt(
const CFGBlock *B,
unsigned StmtIdx,
499 if (StmtIdx == B->
size())
500 HandleBlockExit(B, Pred);
503 SubEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx);
524 if (IsNew) WList->enqueue(Node);
528 const CFGBlock *Block,
unsigned Idx) {
536 WList->enqueue(N, Block, Idx);
543 WList->enqueue(N, Block, Idx+1);
548 WList->enqueue(N, Block, Idx);
553 WList->enqueue(N, Block, Idx+1);
564 WList->enqueue(N, Block, Idx+1);
573 WList->enqueue(Succ, Block, Idx+1);
587 return isNew ? Node :
nullptr;
593 E = Set.
end(); I != E; ++I) {
599 const CFGBlock *Block,
unsigned Idx) {
601 E = Set.
end(); I != E; ++I) {
602 enqueueStmtNode(*I, Block, Idx);
611 N = generateCallExitBeginNode(N);
623 void NodeBuilder::anchor() { }
629 HasGeneratedNodes =
true;
631 ExplodedNode *N =
C.Eng.G.getNode(Loc, State, MarkAsSink, &IsNew);
633 Frontier.erase(FromN);
644 void NodeBuilderWithSinks::anchor() { }
649 E = Frontier.end(); I != E; ++I )
650 EnclosingBldr->addNodes(*I);
653 void BranchNodeBuilder::anchor() { }
659 if (!isFeasible(branch))
664 ExplodedNode *Succ = generateNodeImpl(Loc, State, NodePred);
682 Eng.WList->enqueue(Succ);
700 Eng.WList->enqueue(Succ);
709 assert(Src->succ_rbegin() != Src->succ_rend());
727 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.
~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)
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()
const LocationContext * getLocationContext() const
const CFGBlock * getBlock() const
Returns the CFGblock associated with the worklist unit.
std::vector< bool > & Stack
const CFGBlock * getDst() const
STATISTIC(NumSteps,"The # of steps executed.")
const ProgramStateRef & getState() const
void Add(ExplodedNode *N)
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 StackFrameContext * getCurrentStackFrame() const
Optional< CFGElement > getFirstElement() const
virtual bool hasWork() const =0
void dispatchWorkItem(ExplodedNode *Pred, ProgramPoint Loc, const WorkListUnit &WU)
const Stmt * getStmt() const
ProgramPoint withTag(const ProgramPointTag *tag) const
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)
const LocationContext * getLocationContext() const
virtual bool visitItemsInWorkList(Visitor &V)=0
This node builder keeps track of the generated sink nodes.
static WorkList * makeBFSBlockDFSContents()
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
const CFGBlock * getBlock() const
static WorkList * makeBFS()