forked from OSchip/llvm-project
[analyze] Convert EndOfPath callback to use CheckerContext
Get rid of the EndOfPathBuilder completely. Use the generic NodeBuilder to generate nodes. Enqueue the end of path frontier explicitly. llvm-svn: 142943
This commit is contained in:
parent
52cd8acafc
commit
3eae33412d
|
@ -199,9 +199,9 @@ public:
|
|||
|
||||
class EndPath {
|
||||
template <typename CHECKER>
|
||||
static void _checkEndPath(void *checker, EndOfFunctionNodeBuilder &B,
|
||||
ExprEngine &Eng) {
|
||||
((const CHECKER *)checker)->checkEndPath(B, Eng);
|
||||
static void _checkEndPath(void *checker,
|
||||
CheckerContext &C) {
|
||||
((const CHECKER *)checker)->checkEndPath(C);
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
@ -39,8 +39,8 @@ namespace ento {
|
|||
class ExplodedNodeSet;
|
||||
class ExplodedGraph;
|
||||
class ProgramState;
|
||||
class EndOfFunctionNodeBuilder;
|
||||
class NodeBuilder;
|
||||
struct NodeBuilderContext;
|
||||
class MemRegion;
|
||||
class SymbolReaper;
|
||||
|
||||
|
@ -230,7 +230,9 @@ public:
|
|||
ExprEngine &Eng);
|
||||
|
||||
/// \brief Run checkers for end of path.
|
||||
void runCheckersForEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng);
|
||||
void runCheckersForEndPath(NodeBuilderContext &BC,
|
||||
ExplodedNodeSet &Dst,
|
||||
ExprEngine &Eng);
|
||||
|
||||
/// \brief Run checkers for branch condition.
|
||||
void runCheckersForBranchCondition(const Stmt *condition,
|
||||
|
@ -334,7 +336,7 @@ public:
|
|||
typedef CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>
|
||||
CheckEndAnalysisFunc;
|
||||
|
||||
typedef CheckerFn<void (EndOfFunctionNodeBuilder &, ExprEngine &)>
|
||||
typedef CheckerFn<void (CheckerContext &)>
|
||||
CheckEndPathFunc;
|
||||
|
||||
typedef CheckerFn<void (const Stmt *, NodeBuilder &, ExplodedNode *Pred,
|
||||
|
|
|
@ -171,9 +171,9 @@ public:
|
|||
struct NodeBuilderContext {
|
||||
CoreEngine &Eng;
|
||||
const CFGBlock *Block;
|
||||
ExplodedNode *ContextPred;
|
||||
ExplodedNode *Pred;
|
||||
NodeBuilderContext(CoreEngine &E, const CFGBlock *B, ExplodedNode *N)
|
||||
: Eng(E), Block(B), ContextPred(N) { assert(B); assert(!N->isSink()); }
|
||||
: Eng(E), Block(B), Pred(N) { assert(B); assert(!N->isSink()); }
|
||||
|
||||
/// \brief Return the CFGBlock associated with this builder.
|
||||
const CFGBlock *getBlock() const { return Block; }
|
||||
|
@ -182,10 +182,9 @@ struct NodeBuilderContext {
|
|||
/// visited on the exploded graph path.
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return Eng.WList->getBlockCounter().getNumVisited(
|
||||
ContextPred->getLocationContext()->getCurrentStackFrame(),
|
||||
Pred->getLocationContext()->getCurrentStackFrame(),
|
||||
Block->getBlockID());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// \class NodeBuilder
|
||||
|
@ -289,15 +288,6 @@ public:
|
|||
void addNodes(ExplodedNode *N) { Frontier.Add(N); }
|
||||
};
|
||||
|
||||
class CommonNodeBuilder {
|
||||
protected:
|
||||
ExplodedNode *Pred;
|
||||
CoreEngine &Eng;
|
||||
|
||||
CommonNodeBuilder(CoreEngine* E, ExplodedNode *P) : Pred(P), Eng(*E) {}
|
||||
BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter(); }
|
||||
};
|
||||
|
||||
/// \class StmtNodeBuilder
|
||||
/// \brief This builder class is useful for generating nodes that resulted from
|
||||
/// visiting a statement. The main difference from it's parent NodeBuilder is
|
||||
|
@ -523,47 +513,6 @@ public:
|
|||
const PP_T &getProgramPoint() const { return cast<PP_T>(pp); }
|
||||
};
|
||||
|
||||
class EndOfFunctionNodeBuilder : public CommonNodeBuilder {
|
||||
const CFGBlock &B;
|
||||
const ProgramPointTag *Tag;
|
||||
|
||||
public:
|
||||
bool hasGeneratedNode;
|
||||
|
||||
public:
|
||||
EndOfFunctionNodeBuilder(const CFGBlock *b, ExplodedNode *N, CoreEngine* e,
|
||||
const ProgramPointTag *tag = 0)
|
||||
: CommonNodeBuilder(e, N), B(*b), Tag(tag), hasGeneratedNode(false) {}
|
||||
|
||||
~EndOfFunctionNodeBuilder();
|
||||
|
||||
EndOfFunctionNodeBuilder withCheckerTag(const ProgramPointTag *tag) {
|
||||
return EndOfFunctionNodeBuilder(&B, Pred, &Eng, tag);
|
||||
}
|
||||
|
||||
WorkList &getWorkList() { return *Eng.WList; }
|
||||
|
||||
ExplodedNode *getPredecessor() const { return Pred; }
|
||||
|
||||
unsigned getCurrentBlockCount() const {
|
||||
return getBlockCounter().getNumVisited(
|
||||
Pred->getLocationContext()->getCurrentStackFrame(),
|
||||
B.getBlockID());
|
||||
}
|
||||
|
||||
ExplodedNode *generateNode(const ProgramState *State,
|
||||
ExplodedNode *P = 0,
|
||||
const ProgramPointTag *tag = 0);
|
||||
|
||||
void GenerateCallExitNode(const ProgramState *state);
|
||||
|
||||
const CFGBlock *getBlock() const { return &B; }
|
||||
|
||||
const ProgramState *getState() const {
|
||||
return getPredecessor()->getState();
|
||||
}
|
||||
};
|
||||
|
||||
class CallEnterNodeBuilder {
|
||||
CoreEngine &Eng;
|
||||
|
||||
|
|
|
@ -124,6 +124,8 @@ public:
|
|||
const Stmt *getStmt() const;
|
||||
|
||||
void GenerateAutoTransition(ExplodedNode *N);
|
||||
void enqueueEndOfPath(ExplodedNodeSet &S);
|
||||
void GenerateCallExitNode(ExplodedNode *N);
|
||||
|
||||
/// ViewGraph - Visualize the ExplodedGraph created by executing the
|
||||
/// simulation.
|
||||
|
@ -181,7 +183,7 @@ public:
|
|||
|
||||
/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
|
||||
/// nodes when the control reaches the end of a function.
|
||||
void processEndOfFunction(EndOfFunctionNodeBuilder& builder);
|
||||
void processEndOfFunction(NodeBuilderContext& BC);
|
||||
|
||||
/// Generate the entry node of the callee.
|
||||
void processCallEnter(CallEnterNodeBuilder &builder);
|
||||
|
|
|
@ -82,7 +82,7 @@ public:
|
|||
|
||||
/// Called by CoreEngine. Used to generate end-of-path
|
||||
/// nodes when the control reaches the end of a function.
|
||||
virtual void processEndOfFunction(EndOfFunctionNodeBuilder& builder) = 0;
|
||||
virtual void processEndOfFunction(NodeBuilderContext& BC) = 0;
|
||||
|
||||
// Generate the entry node of the callee.
|
||||
virtual void processCallEnter(CallEnterNodeBuilder &builder) = 0;
|
||||
|
|
|
@ -58,7 +58,7 @@ public:
|
|||
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
|
||||
void checkPostStmt(const CallExpr *S, CheckerContext &C) const;
|
||||
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
|
||||
void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
|
||||
void checkEndPath(CheckerContext &Ctx) const;
|
||||
|
||||
private:
|
||||
typedef std::pair<SymbolRef, const AllocationState*> AllocationPair;
|
||||
|
@ -557,9 +557,8 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
|
|||
}
|
||||
|
||||
// TODO: Remove this after we ensure that checkDeadSymbols are always called.
|
||||
void MacOSKeychainAPIChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
|
||||
ExprEngine &Eng) const {
|
||||
const ProgramState *state = B.getState();
|
||||
void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &Ctx) const {
|
||||
const ProgramState *state = Ctx.getState();
|
||||
AllocatedSetTy AS = state->get<AllocatedData>();
|
||||
if (AS.isEmpty())
|
||||
return;
|
||||
|
@ -575,7 +574,7 @@ void MacOSKeychainAPIChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
|
|||
// allocation, do not report.
|
||||
if (state->getSymVal(I.getKey()) ||
|
||||
definitelyReturnedError(I->second.Region, state,
|
||||
Eng.getSValBuilder())) {
|
||||
Ctx.getSValBuilder())) {
|
||||
continue;
|
||||
}
|
||||
Errors.push_back(std::make_pair(I->first, &I->second));
|
||||
|
@ -585,15 +584,14 @@ void MacOSKeychainAPIChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
|
|||
if (!Changed)
|
||||
return;
|
||||
|
||||
ExplodedNode *N = B.generateNode(state);
|
||||
ExplodedNode *N = Ctx.generateNode(state);
|
||||
if (!N)
|
||||
return;
|
||||
|
||||
// Generate the error reports.
|
||||
for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
|
||||
I != E; ++I) {
|
||||
Eng.getBugReporter().EmitReport(
|
||||
generateAllocatedDataNotReleasedReport(*I, N));
|
||||
Ctx.EmitReport(generateAllocatedDataNotReleasedReport(*I, N));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
|
||||
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
|
||||
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
|
||||
void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
|
||||
void checkEndPath(CheckerContext &C) const;
|
||||
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
|
||||
const ProgramState *evalAssume(const ProgramState *state, SVal Cond,
|
||||
bool Assumption) const;
|
||||
|
@ -604,21 +604,20 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
|
|||
}
|
||||
}
|
||||
|
||||
void MallocChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
|
||||
ExprEngine &Eng) const {
|
||||
const ProgramState *state = B.getState();
|
||||
void MallocChecker::checkEndPath(CheckerContext &Ctx) const {
|
||||
const ProgramState *state = Ctx.getState();
|
||||
RegionStateTy M = state->get<RegionState>();
|
||||
|
||||
for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
|
||||
RefState RS = I->second;
|
||||
if (RS.isAllocated()) {
|
||||
ExplodedNode *N = B.generateNode(state);
|
||||
ExplodedNode *N = Ctx.generateNode(state);
|
||||
if (N) {
|
||||
if (!BT_Leak)
|
||||
BT_Leak.reset(new BuiltinBug("Memory leak",
|
||||
"Allocated memory never released. Potential memory leak."));
|
||||
BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
|
||||
Eng.getBugReporter().EmitReport(R);
|
||||
Ctx.EmitReport(R);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,24 +47,13 @@ class GenericNodeBuilderRefCount {
|
|||
EndOfFunctionNodeBuilder *ENB;
|
||||
public:
|
||||
GenericNodeBuilderRefCount(CheckerContext &c,
|
||||
const ProgramPointTag *t)
|
||||
const ProgramPointTag *t = 0)
|
||||
: C(&c), tag(t), ENB(0) {}
|
||||
|
||||
GenericNodeBuilderRefCount(EndOfFunctionNodeBuilder &enb)
|
||||
: C(0), tag(0), ENB(&enb) {}
|
||||
|
||||
ExplodedNode *MakeNode(const ProgramState *state, ExplodedNode *Pred,
|
||||
bool MarkAsSink = false) {
|
||||
if (C) {
|
||||
return C->generateNode(state, Pred, tag, false, MarkAsSink);
|
||||
}
|
||||
|
||||
assert(ENB);
|
||||
ExplodedNode *N = ENB->generateNode(state, Pred);
|
||||
if (MarkAsSink)
|
||||
N->markAsSink();
|
||||
|
||||
return N;
|
||||
assert(C);
|
||||
return C->generateNode(state, Pred, tag, false, MarkAsSink);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
@ -2445,7 +2434,7 @@ public:
|
|||
SymbolRef Sym, const ProgramState *state) const;
|
||||
|
||||
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
|
||||
void checkEndPath(EndOfFunctionNodeBuilder &Builder, ExprEngine &Eng) const;
|
||||
void checkEndPath(CheckerContext &C) const;
|
||||
|
||||
const ProgramState *updateSymbol(const ProgramState *state, SymbolRef sym,
|
||||
RefVal V, ArgEffect E, RefVal::Kind &hasErr,
|
||||
|
@ -3439,12 +3428,12 @@ RetainCountChecker::processLeaks(const ProgramState *state,
|
|||
return N;
|
||||
}
|
||||
|
||||
void RetainCountChecker::checkEndPath(EndOfFunctionNodeBuilder &Builder,
|
||||
ExprEngine &Eng) const {
|
||||
const ProgramState *state = Builder.getState();
|
||||
GenericNodeBuilderRefCount Bd(Builder);
|
||||
void RetainCountChecker::checkEndPath(CheckerContext &Ctx) const {
|
||||
const ProgramState *state = Ctx.getState();
|
||||
GenericNodeBuilderRefCount Bd(Ctx);
|
||||
RefBindings B = state->get<RefBindings>();
|
||||
ExplodedNode *Pred = Builder.getPredecessor();
|
||||
ExplodedNode *Pred = Ctx.getPredecessor();
|
||||
ExprEngine &Eng = Ctx.getEngine();
|
||||
|
||||
for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
|
||||
llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, Eng,
|
||||
|
|
|
@ -31,7 +31,7 @@ class StackAddrEscapeChecker : public Checker< check::PreStmt<ReturnStmt>,
|
|||
|
||||
public:
|
||||
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
|
||||
void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
|
||||
void checkEndPath(CheckerContext &Ctx) const;
|
||||
private:
|
||||
void EmitStackError(CheckerContext &C, const MemRegion *R,
|
||||
const Expr *RetE) const;
|
||||
|
@ -136,22 +136,22 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
|
|||
}
|
||||
}
|
||||
|
||||
void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
|
||||
ExprEngine &Eng) const {
|
||||
|
||||
const ProgramState *state = B.getState();
|
||||
void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const {
|
||||
const ProgramState *state = Ctx.getState();
|
||||
|
||||
// Iterate over all bindings to global variables and see if it contains
|
||||
// a memory region in the stack space.
|
||||
class CallBack : public StoreManager::BindingsHandler {
|
||||
private:
|
||||
ExprEngine &Eng;
|
||||
CheckerContext &Ctx;
|
||||
const StackFrameContext *CurSFC;
|
||||
public:
|
||||
SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
|
||||
|
||||
CallBack(ExprEngine &Eng, const LocationContext *LCtx)
|
||||
: Eng(Eng), CurSFC(LCtx->getCurrentStackFrame()) {}
|
||||
CallBack(CheckerContext &CC) :
|
||||
Ctx(CC),
|
||||
CurSFC(CC.getPredecessor()->getLocationContext()->getCurrentStackFrame())
|
||||
{}
|
||||
|
||||
bool HandleBinding(StoreManager &SMgr, Store store,
|
||||
const MemRegion *region, SVal val) {
|
||||
|
@ -165,7 +165,7 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
|
|||
|
||||
// Under automated retain release, it is okay to assign a block
|
||||
// directly to a global variable.
|
||||
if (Eng.getContext().getLangOptions().ObjCAutoRefCount &&
|
||||
if (Ctx.getASTContext().getLangOptions().ObjCAutoRefCount &&
|
||||
isa<BlockDataRegion>(vR))
|
||||
return true;
|
||||
|
||||
|
@ -181,14 +181,14 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
|
|||
}
|
||||
};
|
||||
|
||||
CallBack cb(Eng, B.getPredecessor()->getLocationContext());
|
||||
CallBack cb(Ctx);
|
||||
state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
|
||||
|
||||
if (cb.V.empty())
|
||||
return;
|
||||
|
||||
// Generate an error node.
|
||||
ExplodedNode *N = B.generateNode(state);
|
||||
ExplodedNode *N = Ctx.generateNode(state);
|
||||
if (!N)
|
||||
return;
|
||||
|
||||
|
@ -204,7 +204,7 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
|
|||
llvm::SmallString<512> buf;
|
||||
llvm::raw_svector_ostream os(buf);
|
||||
SourceRange range = GenName(os, cb.V[i].second,
|
||||
Eng.getContext().getSourceManager());
|
||||
Ctx.getSourceManager());
|
||||
os << " is still referred to by the global variable '";
|
||||
const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion());
|
||||
os << *VR->getDecl()
|
||||
|
@ -213,7 +213,7 @@ void StackAddrEscapeChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
|
|||
if (range.isValid())
|
||||
report->addRange(range);
|
||||
|
||||
Eng.getBugReporter().EmitReport(report);
|
||||
Ctx.EmitReport(report);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ public:
|
|||
|
||||
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
|
||||
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
|
||||
void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const;
|
||||
void checkEndPath(CheckerContext &Ctx) const;
|
||||
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
|
||||
|
||||
private:
|
||||
|
@ -418,23 +418,22 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,
|
|||
}
|
||||
}
|
||||
|
||||
void StreamChecker::checkEndPath(EndOfFunctionNodeBuilder &B,
|
||||
ExprEngine &Eng) const {
|
||||
const ProgramState *state = B.getState();
|
||||
void StreamChecker::checkEndPath(CheckerContext &Ctx) const {
|
||||
const ProgramState *state = Ctx.getState();
|
||||
typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap;
|
||||
SymMap M = state->get<StreamState>();
|
||||
|
||||
for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
|
||||
StreamState SS = I->second;
|
||||
if (SS.isOpened()) {
|
||||
ExplodedNode *N = B.generateNode(state);
|
||||
ExplodedNode *N = Ctx.generateNode(state);
|
||||
if (N) {
|
||||
if (!BT_ResourceLeak)
|
||||
BT_ResourceLeak.reset(new BuiltinBug("Resource Leak",
|
||||
"Opened File never closed. Potential Resource leak."));
|
||||
BugReport *R = new BugReport(*BT_ResourceLeak,
|
||||
BT_ResourceLeak->getDescription(), N);
|
||||
Eng.getBugReporter().EmitReport(R);
|
||||
Ctx.EmitReport(R);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -298,12 +298,25 @@ void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
|
|||
}
|
||||
|
||||
/// \brief Run checkers for end of path.
|
||||
void CheckerManager::runCheckersForEndPath(EndOfFunctionNodeBuilder &B,
|
||||
// Note, We do not chain the checker output (like in expandGraphWithCheckers)
|
||||
// for this callback since end of path nodes are expected to be final.
|
||||
void CheckerManager::runCheckersForEndPath(NodeBuilderContext &BC,
|
||||
ExplodedNodeSet &Dst,
|
||||
ExprEngine &Eng) {
|
||||
ExplodedNode *Pred = BC.Pred;
|
||||
|
||||
// We define the builder outside of the loop bacause if at least one checkers
|
||||
// creates a sucsessor for Pred, we do not need to generate an
|
||||
// autotransition for it.
|
||||
NodeBuilder Bldr(Pred, Dst, BC);
|
||||
for (unsigned i = 0, e = EndPathCheckers.size(); i != e; ++i) {
|
||||
CheckEndPathFunc fn = EndPathCheckers[i];
|
||||
EndOfFunctionNodeBuilder specialB = B.withCheckerTag(fn.Checker);
|
||||
fn(specialB, Eng);
|
||||
CheckEndPathFunc checkFn = EndPathCheckers[i];
|
||||
|
||||
const ProgramPoint &L = BlockEntrance(BC.Block,
|
||||
Pred->getLocationContext(),
|
||||
checkFn.Checker);
|
||||
CheckerContext C(Bldr, Eng, Pred, L, 0);
|
||||
checkFn(C);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -269,8 +269,8 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
|
|||
&& "EXIT block cannot contain Stmts.");
|
||||
|
||||
// Process the final state transition.
|
||||
EndOfFunctionNodeBuilder Builder(Blk, Pred, this);
|
||||
SubEng.processEndOfFunction(Builder);
|
||||
NodeBuilderContext BuilderCtx(*this, Blk, Pred);
|
||||
SubEng.processEndOfFunction(BuilderCtx);
|
||||
|
||||
// This path is done. Don't enqueue any more nodes.
|
||||
return;
|
||||
|
@ -597,57 +597,6 @@ SwitchNodeBuilder::generateDefaultCaseNode(const ProgramState *St,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
EndOfFunctionNodeBuilder::~EndOfFunctionNodeBuilder() {
|
||||
// Auto-generate an EOP node if one has not been generated.
|
||||
if (!hasGeneratedNode) {
|
||||
// If we are in an inlined call, generate CallExit node.
|
||||
if (Pred->getLocationContext()->getParent())
|
||||
GenerateCallExitNode(Pred->State);
|
||||
else
|
||||
generateNode(Pred->State);
|
||||
}
|
||||
}
|
||||
|
||||
ExplodedNode*
|
||||
EndOfFunctionNodeBuilder::generateNode(const ProgramState *State,
|
||||
ExplodedNode *P,
|
||||
const ProgramPointTag *tag) {
|
||||
hasGeneratedNode = true;
|
||||
bool IsNew;
|
||||
|
||||
ExplodedNode *Node = Eng.G->getNode(BlockEntrance(&B,
|
||||
Pred->getLocationContext(), tag ? tag : Tag),
|
||||
State, &IsNew);
|
||||
|
||||
Node->addPredecessor(P ? P : Pred, *Eng.G);
|
||||
|
||||
if (IsNew) {
|
||||
Eng.G->addEndOfPath(Node);
|
||||
return Node;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void EndOfFunctionNodeBuilder::GenerateCallExitNode(const ProgramState *state) {
|
||||
hasGeneratedNode = true;
|
||||
// Create a CallExit node and enqueue it.
|
||||
const StackFrameContext *LocCtx
|
||||
= cast<StackFrameContext>(Pred->getLocationContext());
|
||||
const Stmt *CE = LocCtx->getCallSite();
|
||||
|
||||
// Use the the callee location context.
|
||||
CallExit Loc(CE, LocCtx);
|
||||
|
||||
bool isNew;
|
||||
ExplodedNode *Node = Eng.G->getNode(Loc, state, &isNew);
|
||||
Node->addPredecessor(Pred, *Eng.G);
|
||||
|
||||
if (isNew)
|
||||
Eng.WList->enqueue(Node);
|
||||
}
|
||||
|
||||
|
||||
void CallEnterNodeBuilder::generateNode(const ProgramState *state) {
|
||||
// Check if the callee is in the same translation unit.
|
||||
if (CalleeCtx->getTranslationUnit() !=
|
||||
|
|
|
@ -1153,11 +1153,42 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) {
|
|||
builder.generateNode(I, state);
|
||||
}
|
||||
|
||||
// TODO: The next two functions should be moved into CoreEngine.
|
||||
void ExprEngine::GenerateCallExitNode(ExplodedNode *N) {
|
||||
// Create a CallExit node and enqueue it.
|
||||
const StackFrameContext *LocCtx
|
||||
= cast<StackFrameContext>(N->getLocationContext());
|
||||
const Stmt *CE = LocCtx->getCallSite();
|
||||
|
||||
// Use the the callee location context.
|
||||
CallExit Loc(CE, LocCtx);
|
||||
|
||||
bool isNew;
|
||||
ExplodedNode *Node = Engine.G->getNode(Loc, N->getState(), &isNew);
|
||||
Node->addPredecessor(N, *Engine.G);
|
||||
|
||||
if (isNew)
|
||||
Engine.WList->enqueue(Node);
|
||||
}
|
||||
|
||||
void ExprEngine::enqueueEndOfPath(ExplodedNodeSet &S) {
|
||||
for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I) {
|
||||
ExplodedNode *N = *I;
|
||||
// If we are in an inlined call, generate CallExit node.
|
||||
if (N->getLocationContext()->getParent())
|
||||
GenerateCallExitNode(N);
|
||||
else
|
||||
Engine.G->addEndOfPath(N);
|
||||
}
|
||||
}
|
||||
|
||||
/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
|
||||
/// nodes when the control reaches the end of a function.
|
||||
void ExprEngine::processEndOfFunction(EndOfFunctionNodeBuilder& builder) {
|
||||
StateMgr.EndPath(builder.getState());
|
||||
getCheckerManager().runCheckersForEndPath(builder, *this);
|
||||
void ExprEngine::processEndOfFunction(NodeBuilderContext& BC) {
|
||||
StateMgr.EndPath(BC.Pred->getState());
|
||||
ExplodedNodeSet Dst;
|
||||
getCheckerManager().runCheckersForEndPath(BC, Dst, *this);
|
||||
enqueueEndOfPath(Dst);
|
||||
}
|
||||
|
||||
/// ProcessSwitch - Called by CoreEngine. Used to generate successor
|
||||
|
|
Loading…
Reference in New Issue