aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h69
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h29
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h4
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp15
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp14
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp305
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp92
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp66
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp41
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineObjC.cpp54
12 files changed, 417 insertions, 280 deletions
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 7450df63c4..6da75a948a 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -19,6 +19,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h"
+#include "clang/Analysis/ProgramPoint.h"
#include <vector>
namespace clang {
@@ -221,7 +222,8 @@ public:
void runCheckersForBind(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location, SVal val,
- const Stmt *S, ExprEngine &Eng);
+ const Stmt *S, ExprEngine &Eng,
+ ProgramPoint::Kind PointKind);
/// \brief Run checkers for end of analysis.
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
index afb19276da..257f9b10af 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -69,7 +69,9 @@ public:
/// \brief Returns the number of times the current block has been visited
/// along the analyzed path.
- unsigned getCurrentBlockCount() {return NB.getCurrentBlockCount();}
+ unsigned getCurrentBlockCount() {
+ return NB.getContext().getCurrentBlockCount();
+ }
ASTContext &getASTContext() {
return Eng.getContext();
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 47682a2ac5..d981b60885 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -39,16 +39,17 @@ class NodeBuilder;
/// at the statement and block-level. The analyses themselves must implement
/// any transfer function logic and the sub-expression level (if any).
class CoreEngine {
- friend class CommonNodeBuilder;
+ friend struct NodeBuilderContext;
friend class NodeBuilder;
friend class StmtNodeBuilder;
+ friend class CommonNodeBuilder;
friend class GenericNodeBuilderImpl;
- friend class BranchNodeBuilder;
friend class IndirectGotoNodeBuilder;
friend class SwitchNodeBuilder;
friend class EndOfFunctionNodeBuilder;
friend class CallEnterNodeBuilder;
friend class CallExitNodeBuilder;
+ friend class ExprEngine;
public:
typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> >
@@ -174,6 +175,18 @@ struct NodeBuilderContext {
ExplodedNode *ContextPred;
NodeBuilderContext(CoreEngine &E, const CFGBlock *B, ExplodedNode *N)
: Eng(E), Block(B), ContextPred(N) { assert(B); assert(!N->isSink()); }
+
+ /// \brief Return the CFGBlock associated with this builder.
+ const CFGBlock *getBlock() const { return Block; }
+
+ /// \brief Returns the number of times the current basic block has been
+ /// visited on the exploded graph path.
+ unsigned getCurrentBlockCount() const {
+ return Eng.WList->getBlockCounter().getNumVisited(
+ ContextPred->getLocationContext()->getCurrentStackFrame(),
+ Block->getBlockID());
+ }
+
};
/// This is the simplest builder which generates nodes in the ExplodedGraph.
@@ -193,8 +206,6 @@ protected:
/// the builder dies.
ExplodedNodeSet &Frontier;
- BlockCounter getBlockCounter() const { return C.Eng.WList->getBlockCounter();}
-
/// Checkes if the results are ready.
virtual bool checkResults() {
if (!Finalized)
@@ -271,19 +282,8 @@ public:
return Frontier.end();
}
- /// \brief Return the CFGBlock associated with this builder.
- const CFGBlock *getBlock() const { return C.Block; }
-
const NodeBuilderContext &getContext() { return C; }
- /// \brief Returns the number of times the current basic block has been
- /// visited on the exploded graph path.
- unsigned getCurrentBlockCount() const {
- return getBlockCounter().getNumVisited(
- C.ContextPred->getLocationContext()->getCurrentStackFrame(),
- C.Block->getBlockID());
- }
-
void takeNodes(const ExplodedNodeSet &S) {
for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I )
Frontier.erase(*I);
@@ -306,7 +306,7 @@ public:
class CommonNodeBuilder {
protected:
ExplodedNode *Pred;
- CoreEngine& Eng;
+ CoreEngine &Eng;
CommonNodeBuilder(CoreEngine* E, ExplodedNode *P) : Pred(P), Eng(*E) {}
BlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter(); }
@@ -314,21 +314,38 @@ protected:
class PureStmtNodeBuilder: public NodeBuilder {
+ NodeBuilder *EnclosingBldr;
public:
PureStmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
- const NodeBuilderContext &Ctx)
- : NodeBuilder(SrcNode, DstSet, Ctx) {}
+ const NodeBuilderContext &Ctx, NodeBuilder *Enclosing = 0)
+ : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) {
+ if (EnclosingBldr)
+ EnclosingBldr->takeNodes(SrcNode);
+ }
PureStmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
- const NodeBuilderContext &Ctx)
- : NodeBuilder(SrcSet, DstSet, Ctx) {}
+ const NodeBuilderContext &Ctx, NodeBuilder *Enclosing = 0)
+ : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) {
+ if (EnclosingBldr)
+ for (ExplodedNodeSet::iterator I = SrcSet.begin(),
+ E = SrcSet.end(); I != E; ++I )
+ EnclosingBldr->takeNodes(*I);
+
+ }
+
+ virtual ~PureStmtNodeBuilder() {
+ if (EnclosingBldr)
+ for (ExplodedNodeSet::iterator I = Frontier.begin(),
+ E = Frontier.end(); I != E; ++I )
+ EnclosingBldr->addNodes(*I);
+ }
ExplodedNode *generateNode(const Stmt *S,
ExplodedNode *Pred,
const ProgramState *St,
- ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
bool MarkAsSink = false,
const ProgramPointTag *tag = 0,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
bool Purging = false) {
if (Purging) {
assert(K == ProgramPoint::PostStmtKind);
@@ -339,6 +356,14 @@ public:
Pred->getLocationContext(), tag);
return generateNodeImpl(L, St, Pred, MarkAsSink);
}
+
+ ExplodedNode *generateNode(const ProgramPoint &PP,
+ ExplodedNode *Pred,
+ const ProgramState *State,
+ bool MarkAsSink = false) {
+ return generateNodeImpl(PP, State, Pred, MarkAsSink);
+ }
+
};
class StmtNodeBuilder : public NodeBuilder {
@@ -360,8 +385,6 @@ public:
PurgingDeadSymbols(false), BuildSinks(false), hasGeneratedNode(false),
PointKind(ProgramPoint::PostStmtKind), Tag(0) {}
- virtual ~StmtNodeBuilder();
-
ExplodedNode *generateNode(const Stmt *S,
const ProgramState *St,
ExplodedNode *Pred,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index a593fac99a..fdd3c47e81 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -120,12 +120,16 @@ public:
StmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; }
const NodeBuilderContext &getBuilderContext() {
- assert(Builder);
- return Builder->getContext();
+ assert(currentBuilderContext);
+ return *currentBuilderContext;
}
bool isObjCGCEnabled() { return ObjCGCEnabled; }
+ const Stmt *getStmt() const;
+
+ void GenerateAutoTransition(ExplodedNode *N);
+
/// ViewGraph - Visualize the ExplodedGraph created by executing the
/// simulation.
void ViewGraph(bool trim = false);
@@ -141,17 +145,14 @@ public:
/// processCFGElement - Called by CoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a CFG element.
- void processCFGElement(const CFGElement E, StmtNodeBuilder& Bldr,
- ExplodedNode *Pred);
+ void processCFGElement(const CFGElement E, ExplodedNode *Pred,
+ unsigned StmtIdx, NodeBuilderContext *Ctx);
- void ProcessStmt(const CFGStmt S, StmtNodeBuilder &builder,
- ExplodedNode *Pred);
+ void ProcessStmt(const CFGStmt S, ExplodedNode *Pred);
- void ProcessInitializer(const CFGInitializer I, StmtNodeBuilder &Bldr,
- ExplodedNode *Pred);
+ void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred);
- void ProcessImplicitDtor(const CFGImplicitDtor D, StmtNodeBuilder &builder,
- ExplodedNode *Pred);
+ void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred);
void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D,
StmtNodeBuilder &builder, ExplodedNode *Pred);
@@ -431,8 +432,9 @@ public:
}
protected:
- void evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg,
- ExplodedNode *Pred, const ProgramState *state);
+ void evalObjCMessage(PureStmtNodeBuilder &Bldr, const ObjCMessage &msg,
+ ExplodedNode *Pred, const ProgramState *state,
+ bool GenSink);
const ProgramState *invalidateArguments(const ProgramState *State,
const CallOrObjCMessage &Call,
@@ -444,7 +446,8 @@ protected:
/// evalBind - Handle the semantics of binding a value to a specific location.
/// This method is used by evalStore, VisitDeclStmt, and others.
void evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred,
- SVal location, SVal Val, bool atDeclInit = false);
+ SVal location, SVal Val, bool atDeclInit = false,
+ ProgramPoint::Kind PP = ProgramPoint::PostStmtKind);
public:
// FIXME: 'tag' should be removed, and a LocationContext should be used
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
index e891e8fc42..a23b71ab31 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
@@ -55,8 +55,8 @@ public:
/// Called by CoreEngine. Used to generate new successor
/// nodes by processing the 'effects' of a block-level statement.
- virtual void processCFGElement(const CFGElement E, StmtNodeBuilder& builder,
- ExplodedNode* Pred)=0;
+ virtual void processCFGElement(const CFGElement E, ExplodedNode* Pred,
+ unsigned StmtIdx, NodeBuilderContext *Ctx)=0;
/// Called by CoreEngine when it starts processing a CFGBlock. The
/// SubEngine is expected to populate dstNodes with new nodes representing
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index e77c677be0..aac181fdb4 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -245,6 +245,7 @@ namespace {
}
/// \brief Run checkers for load/store of a location.
+
void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location, bool isLoad,
@@ -261,18 +262,19 @@ namespace {
SVal Val;
const Stmt *S;
ExprEngine &Eng;
+ ProgramPoint::Kind PointKind;
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
CheckBindContext(const CheckersTy &checkers,
- SVal loc, SVal val, const Stmt *s, ExprEngine &eng)
- : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng) { }
+ SVal loc, SVal val, const Stmt *s, ExprEngine &eng,
+ ProgramPoint::Kind PK)
+ : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PointKind(PK) {}
void runChecker(CheckerManager::CheckBindFunc checkFn,
NodeBuilder &Bldr, ExplodedNode *Pred) {
- ProgramPoint::Kind K = ProgramPoint::PreStmtKind;
- const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
+ const ProgramPoint &L = ProgramPoint::getProgramPoint(S, PointKind,
Pred->getLocationContext(), checkFn.Checker);
CheckerContext C(Bldr, Eng, Pred, L, 0);
@@ -285,8 +287,9 @@ namespace {
void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
SVal location, SVal val,
- const Stmt *S, ExprEngine &Eng) {
- CheckBindContext C(BindCheckers, location, val, S, Eng);
+ const Stmt *S, ExprEngine &Eng,
+ ProgramPoint::Kind PointKind) {
+ CheckBindContext C(BindCheckers, location, val, S, Eng, PointKind);
expandGraphWithCheckers(C, Dst, Src);
}
diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 6616e065d3..809379e4ac 100644
--- a/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -315,9 +315,7 @@ void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
// Process the entrance of the block.
if (CFGElement E = L.getFirstElement()) {
NodeBuilderContext Ctx(*this, L.getBlock(), Pred);
- ExplodedNodeSet Dst;
- StmtNodeBuilder Builder(Pred, Dst, 0, Ctx);
- SubEng.processCFGElement(E, Builder, Pred);
+ SubEng.processCFGElement(E, Pred, 0, &Ctx);
}
else
HandleBlockExit(L.getBlock(), Pred);
@@ -436,9 +434,7 @@ void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
HandleBlockExit(B, Pred);
else {
NodeBuilderContext Ctx(*this, B, Pred);
- ExplodedNodeSet Dst;
- StmtNodeBuilder Builder(Pred, Dst, StmtIdx, Ctx);
- SubEng.processCFGElement((*B)[StmtIdx], Builder, Pred);
+ SubEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx);
}
}
@@ -510,12 +506,6 @@ ExplodedNode* NodeBuilder::generateNodeImpl(const ProgramPoint &Loc,
return (IsNew ? N : 0);
}
-StmtNodeBuilder::~StmtNodeBuilder() {
- for (iterator I=Frontier.begin(), E=Frontier.end(); I!=E; ++I)
- if (!(*I)->isSink())
- GenerateAutoTransition(*I);
-}
-
void StmtNodeBuilder::GenerateAutoTransition(ExplodedNode *N) {
assert (!N->isSink());
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 5999dc6bb1..0b40c9aa4d 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -197,30 +197,77 @@ void ExprEngine::processEndWorklist(bool hasWorkRemaining) {
getCheckerManager().runCheckersForEndAnalysis(G, BR, *this);
}
-void ExprEngine::processCFGElement(const CFGElement E,
- StmtNodeBuilder& Bldr,
- ExplodedNode *Pred) {
+void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
+ unsigned StmtIdx, NodeBuilderContext *Ctx) {
+ currentStmtIdx = StmtIdx;
+ currentBuilderContext = Ctx;
+
switch (E.getKind()) {
case CFGElement::Invalid:
llvm_unreachable("Unexpected CFGElement kind.");
case CFGElement::Statement:
- ProcessStmt(const_cast<Stmt*>(E.getAs<CFGStmt>()->getStmt()), Bldr, Pred);
+ ProcessStmt(const_cast<Stmt*>(E.getAs<CFGStmt>()->getStmt()), Pred);
return;
case CFGElement::Initializer:
- ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(),
- Bldr, Pred);
+ ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(), Pred);
return;
case CFGElement::AutomaticObjectDtor:
case CFGElement::BaseDtor:
case CFGElement::MemberDtor:
case CFGElement::TemporaryDtor:
- ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), Bldr, Pred);
+ ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), Pred);
return;
}
}
-void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder,
+const Stmt *ExprEngine::getStmt() const {
+ const CFGStmt *CS = (*currentBuilderContext->getBlock())[currentStmtIdx].getAs<CFGStmt>();
+ return CS ? CS->getStmt() : 0;
+}
+
+// TODO: Adding nodes to the worklist shoudl be a function inside CoreEngine.
+void ExprEngine::GenerateAutoTransition(ExplodedNode *N) {
+ assert (!N->isSink());
+ const CFGBlock *Block = currentBuilderContext->getBlock();
+ unsigned Idx = currentStmtIdx;
+
+ // Check if this node entered a callee.
+ if (isa<CallEnter>(N->getLocation())) {
+ // Still use the index of the CallExpr. It's needed to create the callee
+ // StackFrameContext.
+ Engine.WList->enqueue(N, Block, Idx);
+ return;
+ }
+
+ // Do not create extra nodes. Move to the next CFG element.
+ if (isa<PostInitializer>(N->getLocation())) {
+ Engine.WList->enqueue(N, Block, Idx+1);
+ return;
+ }
+
+ PostStmt Loc(getStmt(), N->getLocationContext());
+
+ if (Loc == N->getLocation()) {
+ // Note: 'N' should be a fresh node because otherwise it shouldn't be
+ // a member of Deferred.
+ Engine.WList->enqueue(N, Block, Idx+1);
+ return;
+ }
+
+ bool IsNew;
+ ExplodedNode *Succ = Engine.G->getNode(Loc, N->getState(), &IsNew);
+ Succ->addPredecessor(N, *Engine.G);
+
+ if (IsNew)
+ Engine.WList->enqueue(Succ, Block, Idx+1);
+}
+
+
+void ExprEngine::ProcessStmt(const CFGStmt S,
ExplodedNode *Pred) {
+ ExplodedNodeSet TopDst;
+ StmtNodeBuilder builder(Pred, TopDst, currentStmtIdx, *currentBuilderContext);
+
// TODO: Use RAII to remove the unnecessary, tagged nodes.
//RegisterCreatedNodes registerCreatedNodes(getGraph());
@@ -230,9 +277,6 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder,
StateMgr.recycleUnusedStates();
currentStmt = S.getStmt();
- currentStmtIdx = builder.getIndex();
- currentBuilderContext = &builder.getContext();
-
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
currentStmt->getLocStart(),
"Error evaluating statement");
@@ -268,15 +312,15 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder,
// up. Since no symbols are dead, we can optimize and not clean out
// the constraint manager.
CleanedNode =
- Builder->generateNode(currentStmt, CleanedState, EntryNode, &cleanupTag);
+ builder.generateNode(currentStmt, CleanedState, EntryNode, &cleanupTag);
Tmp.Add(CleanedNode);
} else {
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->hasGeneratedNode);
+ SaveAndRestore<bool> OldSink(builder.BuildSinks);
+ SaveOr OldHasGen(builder.hasGeneratedNode);
- SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols);
- Builder->PurgingDeadSymbols = true;
+ SaveAndRestore<bool> OldPurgeDeadSymbols(builder.PurgingDeadSymbols);
+ builder.PurgingDeadSymbols = true;
// Call checkers with the non-cleaned state so that they could query the
// values of the soon to be dead symbols.
@@ -306,18 +350,25 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder,
// generate a transition to that state.
const ProgramState *CleanedCheckerSt =
StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState);
- ExplodedNode *CleanedNode = Builder->generateNode(currentStmt,
+ ExplodedNode *CleanedNode = builder.generateNode(currentStmt,
CleanedCheckerSt, *I,
&cleanupTag);
Tmp.Add(CleanedNode);
}
}
+ ExplodedNodeSet AllDst;
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- // TODO: Remove Dest set, it's no longer needed.
ExplodedNodeSet Dst;
// Visit the statement.
Visit(currentStmt, *I, Dst);
+ AllDst.insert(Dst);
+ }
+
+ for (ExplodedNodeSet::iterator I = AllDst.begin(),
+ E = AllDst.end(); I != E; ++I) {
+ assert(!(*I)->isSink());
+ GenerateAutoTransition(*I);
}
// NULL out these variables to cleanup.
@@ -328,8 +379,10 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder,
}
void ExprEngine::ProcessInitializer(const CFGInitializer Init,
- StmtNodeBuilder &builder,
ExplodedNode *pred) {
+ ExplodedNodeSet Dst;
+ StmtNodeBuilder Bldr(pred, Dst, currentStmtIdx, *currentBuilderContext);
+
// We don't set EntryNode and currentStmt. And we don't clean up state.
const CXXCtorInitializer *BMI = Init.getInitializer();
const StackFrameContext *stackFrame = cast<StackFrameContext>(pred->getLocationContext());
@@ -358,7 +411,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
PostInitializer PP(BMI, stackFrame);
// Builder automatically add the generated node to the deferred set,
// which are processed in the builder's dtor.
- builder.generateNode(PP, state, Pred);
+ Bldr.generateNode(PP, state, Pred);
}
return;
}
@@ -373,14 +426,20 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
getStoreManager().evalDerivedToBase(thisVal, ctorExpr->getType());
const MemRegion *baseReg = baseVal.getAsRegion();
assert(baseReg);
- Builder = &builder;
+ Builder = &Bldr;
ExplodedNodeSet dst;
VisitCXXConstructExpr(ctorExpr, baseReg, pred, dst);
+ for (ExplodedNodeSet::iterator I = dst.begin(),
+ E = dst.end(); I != E; ++I) {
+ GenerateAutoTransition(*I);
+ }
}
void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
- StmtNodeBuilder &builder,
- ExplodedNode *Pred) {
+ ExplodedNode *Pred) {
+ ExplodedNodeSet Dst;
+ StmtNodeBuilder builder(Pred, Dst, currentStmtIdx, *currentBuilderContext);
+
Builder = &builder;
switch (D.getKind()) {
@@ -399,6 +458,11 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
default:
llvm_unreachable("Unexpected dtor kind.");
}
+
+ for (ExplodedNodeSet::iterator I = Dst.begin(),
+ E = Dst.end(); I != E; ++I) {
+ GenerateAutoTransition(*I);
+ }
}
void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor dtor,
@@ -440,6 +504,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
S->getLocStart(),
"Error evaluating statement");
+ PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);
// Expressions to ignore.
if (const Expr *Ex = dyn_cast<Expr>(S))
@@ -449,10 +514,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// this check when we KNOW that there is no block-level subexpression.
// The motivation is that this check requires a hashtable lookup.
- if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S)) {
- Dst.Add(Pred);
+ if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S))
return;
- }
switch (S->getStmtClass()) {
// C++ and ARC stuff we don't support yet.
@@ -479,22 +542,17 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::SubstNonTypeTemplateParmPackExprClass:
case Stmt::SEHTryStmtClass:
case Stmt::SEHExceptStmtClass:
- case Stmt::SEHFinallyStmtClass:
- {
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- Builder->BuildSinks = true;
- const ExplodedNode *node = MakeNode(Dst, S, Pred, Pred->getState());
- Engine.addAbortedBlock(node, Builder->getBlock());
+ case Stmt::SEHFinallyStmtClass: {
+ const ExplodedNode *node = Bldr.generateNode(S, Pred, Pred->getState());
+ Engine.addAbortedBlock(node, currentBuilderContext->getBlock());
break;
}
// We don't handle default arguments either yet, but we can fake it
// for now by just skipping them.
case Stmt::SubstNonTypeTemplateParmExprClass:
- case Stmt::CXXDefaultArgExprClass: {
- Dst.Add(Pred);
+ case Stmt::CXXDefaultArgExprClass:
break;
- }
case Stmt::ParenExprClass:
llvm_unreachable("ParenExprs already handled.");
@@ -525,31 +583,33 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// GNU __null is a pointer-width integer, not an actual pointer.
const ProgramState *state = Pred->getState();
state = state->BindExpr(S, svalBuilder.makeIntValWithPtrWidth(0, false));
- MakeNode(Dst, S, Pred, state);
+ Bldr.generateNode(S, Pred, state);
break;
}
case Stmt::ObjCAtSynchronizedStmtClass:
+ Bldr.takeNodes(Pred);
VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::ObjCPropertyRefExprClass:
// Implicitly handled by Environment::getSVal().
- Dst.Add(Pred);
break;
case Stmt::ImplicitValueInitExprClass: {
const ProgramState *state = Pred->getState();
QualType ty = cast<ImplicitValueInitExpr>(S)->getType();
SVal val = svalBuilder.makeZeroVal(ty);
- MakeNode(Dst, S, Pred, state->BindExpr(S, val));
+ Bldr.generateNode(S, Pred, state->BindExpr(S, val));
break;
}
- case Stmt::ExprWithCleanupsClass: {
+ case Stmt::ExprWithCleanupsClass:
+ Bldr.takeNodes(Pred);
Visit(cast<ExprWithCleanups>(S)->getSubExpr(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
- }
// Cases not handled yet; but will handle some day.
case Stmt::DesignatedInitExprClass:
@@ -583,39 +643,52 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::FloatingLiteralClass:
case Stmt::SizeOfPackExprClass:
case Stmt::CXXNullPtrLiteralExprClass:
- Dst.Add(Pred); // No-op. Simply propagate the current state unchanged.
+ // No-op. Simply propagate the current state unchanged.
break;
case Stmt::ArraySubscriptExprClass:
+ Bldr.takeNodes(Pred);
VisitLvalArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::AsmStmtClass:
+ Bldr.takeNodes(Pred);
VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::BlockDeclRefExprClass: {
+ Bldr.takeNodes(Pred);
const BlockDeclRefExpr *BE = cast<BlockDeclRefExpr>(S);
VisitCommonDeclRefExpr(BE, BE->getDecl(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::BlockExprClass:
+ Bldr.takeNodes(Pred);
VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::BinaryOperatorClass: {
const BinaryOperator* B = cast<BinaryOperator>(S);
if (B->isLogicalOp()) {
+ Bldr.takeNodes(Pred);
VisitLogicalExpr(B, Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
else if (B->getOpcode() == BO_Comma) {
const ProgramState *state = Pred->getState();
- MakeNode(Dst, B, Pred, state->BindExpr(B, state->getSVal(B->getRHS())));
+ Bldr.generateNode(B, Pred,
+ state->BindExpr(B, state->getSVal(B->getRHS())));
break;
}
+ Bldr.takeNodes(Pred);
+
if (AMgr.shouldEagerlyAssume() &&
(B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp;
@@ -625,13 +698,16 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
else
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CallExprClass:
case Stmt::CXXOperatorCallExprClass:
case Stmt::CXXMemberCallExprClass: {
+ Bldr.takeNodes(Pred);
VisitCallExpr(cast<CallExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
@@ -640,58 +716,78 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
const CXXConstructExpr *C = cast<CXXConstructExpr>(S);
// For block-level CXXConstructExpr, we don't have a destination region.
// Let VisitCXXConstructExpr() create one.
+ Bldr.takeNodes(Pred);
VisitCXXConstructExpr(C, 0, Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CXXNewExprClass: {
+ Bldr.takeNodes(Pred);
const CXXNewExpr *NE = cast<CXXNewExpr>(S);
VisitCXXNewExpr(NE, Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CXXDeleteExprClass: {
+ Bldr.takeNodes(Pred);
const CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S);
VisitCXXDeleteExpr(CDE, Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
// FIXME: ChooseExpr is really a constant. We need to fix
// the CFG do not model them as explicit control-flow.
case Stmt::ChooseExprClass: { // __builtin_choose_expr
+ Bldr.takeNodes(Pred);
const ChooseExpr *C = cast<ChooseExpr>(S);
VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CompoundAssignOperatorClass:
+ Bldr.takeNodes(Pred);
VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::CompoundLiteralExprClass:
+ Bldr.takeNodes(Pred);
VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: { // '?' operator
+ Bldr.takeNodes(Pred);
const AbstractConditionalOperator *C
= cast<AbstractConditionalOperator>(S);
VisitGuardedExpr(C, C->getTrueExpr(), C->getFalseExpr(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::CXXThisExprClass:
+ Bldr.takeNodes(Pred);
VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::DeclRefExprClass: {
+ Bldr.takeNodes(Pred);
const DeclRefExpr *DE = cast<DeclRefExpr>(S);
VisitCommonDeclRefExpr(DE, DE->getDecl(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::DeclStmtClass:
+ Bldr.takeNodes(Pred);
VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::ImplicitCastExprClass:
@@ -702,6 +798,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::CXXConstCastExprClass:
case Stmt::CXXFunctionalCastExprClass:
case Stmt::ObjCBridgedCastExprClass: {
+ Bldr.takeNodes(Pred);
const CastExpr *C = cast<CastExpr>(S);
// Handle the previsit checks.
ExplodedNodeSet dstPrevisit;
@@ -716,58 +813,76 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// Handle the postvisit checks.
getCheckerManager().runCheckersForPostStmt(Dst, dstExpr, C, *this);
+ Bldr.addNodes(Dst);
break;
}
case Expr::MaterializeTemporaryExprClass: {
+ Bldr.takeNodes(Pred);
const MaterializeTemporaryExpr *Materialize
= cast<MaterializeTemporaryExpr>(S);
if (!Materialize->getType()->isRecordType())
CreateCXXTemporaryObject(Materialize, Pred, Dst);
else
Visit(Materialize->GetTemporaryExpr(), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
}
case Stmt::InitListExprClass:
+ Bldr.takeNodes(Pred);
VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::MemberExprClass:
+ Bldr.takeNodes(Pred);
VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
+
case Stmt::ObjCIvarRefExprClass:
+ Bldr.takeNodes(Pred);
VisitLvalObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::ObjCForCollectionStmtClass:
+ Bldr.takeNodes(Pred);
VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::ObjCMessageExprClass:
+ Bldr.takeNodes(Pred);
VisitObjCMessage(cast<ObjCMessageExpr>(S), Pred, Dst);
+ Bldr.addNodes(Dst);
break;
case Stmt::ObjCAtThrowStmtClass: {
// FIXME: This is