diff options
-rw-r--r-- | include/clang/StaticAnalyzer/Core/CheckerManager.h | 4 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h | 4 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h | 69 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h | 29 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h | 4 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/CheckerManager.cpp | 15 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/CoreEngine.cpp | 14 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 305 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineC.cpp | 92 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 66 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp | 41 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineObjC.cpp | 54 |
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 not complete. We basically treat @throw as // an abort. - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - Builder->BuildSinks = true; - MakeNode(Dst, S, Pred, Pred->getState()); + Bldr.generateNode(S, Pred, Pred->getState()); break; } case Stmt::ReturnStmtClass: + Bldr.takeNodes(Pred); VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::OffsetOfExprClass: + Bldr.takeNodes(Pred); VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::UnaryExprOrTypeTraitExprClass: + Bldr.takeNodes(Pred); VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::StmtExprClass: { @@ -777,36 +892,35 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, // Empty statement expression. assert(SE->getType() == getContext().VoidTy && "Empty statement expression must have void type."); - Dst.Add(Pred); break; } if (Expr *LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) { const ProgramState *state = Pred->getState(); - MakeNode(Dst, SE, Pred, state->BindExpr(SE, state->getSVal(LastExpr))); + Bldr.generateNode(SE, Pred, + state->BindExpr(SE, state->getSVal(LastExpr))); } - else - Dst.Add(Pred); - break; } case Stmt::StringLiteralClass: { const ProgramState *state = Pred->getState(); SVal V = state->getLValue(cast<StringLiteral>(S)); - MakeNode(Dst, S, Pred, state->BindExpr(S, V)); + Bldr.generateNode(S, Pred, state->BindExpr(S, V)); return; } case Stmt::UnaryOperatorClass: { + Bldr.takeNodes(Pred); const UnaryOperator *U = cast<UnaryOperator>(S); - if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UO_LNot)) { + if (AMgr.shouldEagerlyAssume() && (U->getOpcode() == UO_LNot)) { ExplodedNodeSet Tmp; VisitUnaryOperator(U, Pred, Tmp); evalEagerlyAssume(Dst, Tmp, U); } else VisitUnaryOperator(U, Pred, Dst); + Bldr.addNodes(Dst); break; } } @@ -1189,6 +1303,8 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); + const ProgramState *state = Pred->getState(); if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { @@ -1204,20 +1320,20 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, V = UnknownVal(); } - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), - ProgramPoint::PostLValueKind); + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, V), false, 0, + ProgramPoint::PostLValueKind); return; } if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D)) { assert(!Ex->isLValue()); SVal V = svalBuilder.makeIntVal(ED->getInitVal()); - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V)); + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, V)); return; } if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { SVal V = svalBuilder.getFunctionPointer(FD); - MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), - ProgramPoint::PostLValueKind); + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, V), false, 0, + ProgramPoint::PostLValueKind); return; } assert (false && @@ -1236,13 +1352,16 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, ExplodedNodeSet checkerPreStmt; getCheckerManager().runCheckersForPreStmt(checkerPreStmt, Pred, A, *this); + PureStmtNodeBuilder Bldr(checkerPreStmt, Dst, *currentBuilderContext, Builder); + for (ExplodedNodeSet::iterator it = checkerPreStmt.begin(), ei = checkerPreStmt.end(); it != ei; ++it) { const ProgramState *state = (*it)->getState(); SVal V = state->getLValue(A->getType(), state->getSVal(Idx), state->getSVal(Base)); assert(A->isLValue()); - MakeNode(Dst, A, *it, state->BindExpr(A, V), ProgramPoint::PostLValueKind); + Bldr.generateNode(A, *it, state->BindExpr(A, V), + false, 0, ProgramPoint::PostLValueKind); } } @@ -1250,10 +1369,13 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); Decl *member = M->getMemberDecl(); if (VarDecl *VD = dyn_cast<VarDecl>(member)) { assert(M->isLValue()); + Bldr.takeNodes(Pred); VisitCommonDeclRefExpr(M, VD, Pred, Dst); + Bldr.addNodes(Dst); return; } @@ -1270,7 +1392,7 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, // temporary struct object, see test/Analysis/fields.c: // (p = getit()).x isa<nonloc::SymbolVal>(baseExprVal)) { - MakeNode(Dst, M, Pred, state->BindExpr(M, UnknownVal())); + Bldr.generateNode(M, Pred, state->BindExpr(M, UnknownVal())); return; } @@ -1281,25 +1403,29 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, // For all other cases, compute an lvalue. SVal L = state->getLValue(field, baseExprVal); if (M->isLValue()) - MakeNode(Dst, M, Pred, state->BindExpr(M, L), ProgramPoint::PostLValueKind); - else + Bldr.generateNode(M, Pred, state->BindExpr(M, L), false, 0, + ProgramPoint::PostLValueKind); + else { + Bldr.takeNodes(Pred); evalLoad(Dst, M, Pred, state, L); + Bldr.addNodes(Dst); + } } /// evalBind - Handle the semantics of binding a value to a specific location. /// This method is used by evalStore and (soon) VisitDeclStmt, and others. void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred, - SVal location, SVal Val, bool atDeclInit) { + SVal location, SVal Val, bool atDeclInit, + ProgramPoint::Kind PointKind) { // Do a previsit of the bind. ExplodedNodeSet CheckedSet; getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val, - StoreE, *this); + StoreE, *this, PointKind); // TODO:AZ Remove TmpDst after NB refactoring is done. ExplodedNodeSet TmpDst; - Builder->takeNodes(CheckedSet); PureStmtNodeBuilder Bldr(CheckedSet, TmpDst, *currentBuilderContext); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); @@ -1315,9 +1441,9 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, state = state->bindLoc(location, Val); } - Bldr.generateNode(StoreE, *I, state); + Bldr.generateNode(StoreE, *I, state, false, 0, PointKind); } - Builder->addNodes(TmpDst); + Dst.insert(TmpDst); } @@ -1357,11 +1483,9 @@ void ExprEngine::evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, if (location.isUndef()) return; - SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind, - ProgramPoint::PostStoreKind); - for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) - evalBind(Dst, StoreE, *NI, location, Val); + evalBind(Dst, StoreE, *NI, location, Val, false, + ProgramPoint::PostStoreKind); } void ExprEngine::evalLoad(ExplodedNodeSet &Dst, const Expr *Ex, @@ -1411,30 +1535,28 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst, const Expr *Ex, // Evaluate the location (checks for bad dereferences). ExplodedNodeSet Tmp; evalLocation(Tmp, Ex, Pred, state, location, tag, true); - if (Tmp.empty()) return; + PureStmtNodeBuilder Bldr(Tmp, Dst, *currentBuilderContext, Builder); if (location.isUndef()) return; - SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind); - // Proceed with the load. for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) { state = (*NI)->getState(); if (location.isUnknown()) { // This is important. We must nuke the old binding. - MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, UnknownVal()), - ProgramPoint::PostLoadKind, tag); + Bldr.generateNode(Ex, *NI, state->BindExpr(Ex, UnknownVal()), + false, tag, ProgramPoint::PostLoadKind); } else { if (LoadTy.isNull()) LoadTy = Ex->getType(); SVal V = state->getSVal(cast<Loc>(location), LoadTy); - MakeNode(Dst, Ex, *NI, state->bindExprAndLocation(Ex, location, V), - ProgramPoint::PostLoadKind, tag); + Bldr.generateNode(Ex, *NI, state->bindExprAndLocation(Ex, location, V), + false, tag, ProgramPoint::PostLoadKind); } } } @@ -1443,16 +1565,16 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S, ExplodedNode *Pred, const ProgramState *state, SVal location, const ProgramPointTag *tag, bool isLoad) { + PureStmtNodeBuilder BldrTop(Pred, Dst, *currentBuilderContext, Builder); // Early checks for performance reason. if (location.isUnknown()) { - Dst.Add(Pred); return; } ExplodedNodeSet Src; - if (Pred->getState() == state) { - Src.Add(Pred); - } else { + BldrTop.takeNodes(Pred); + PureStmtNodeBuilder Bldr(Pred, Src, *currentBuilderContext); + if (Pred->getState() != state) { // Associate this new state with an ExplodedNode. // FIXME: If I pass null tag, the graph is incorrect, e.g for // int *p; @@ -1465,11 +1587,12 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S, // FIXME: why is 'tag' not used instead of etag? static SimpleProgramPointTag etag("ExprEngine: Location"); - ExplodedNode *N = Builder->generateNode(S, state, Pred, &etag); - Src.Add(N ? N : Pred); + Bldr.generateNode(S, Pred, state, false, &etag); } - getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S, + ExplodedNodeSet Tmp; + getCheckerManager().runCheckersForLocation(Tmp, Src, location, isLoad, S, *this); + BldrTop.addNodes(Tmp); } bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, @@ -1558,17 +1681,15 @@ ExprEngine::getEagerlyAssumeTags() { void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, const Expr *Ex) { - + PureStmtNodeBuilder Bldr(Src, Dst, *currentBuilderContext, Builder); for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) { ExplodedNode *Pred = *I; - // Test if the previous node was as the same expression. This can happen // when the expression fails to evaluate to anything meaningful and // (as an optimization) we don't generate a node. ProgramPoint P = Pred->getLocation(); if (!isa<PostStmt>(P) || cast<PostStmt>(P).getStmt() != Ex) { - Dst.Add(Pred); continue; } @@ -1582,18 +1703,16 @@ void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, if (const ProgramState *StateTrue = state->assume(*SEV, true)) { SVal Val = svalBuilder.makeIntVal(1U, Ex->getType()); StateTrue = StateTrue->BindExpr(Ex, Val); - Dst.Add(Builder->generateNode(Ex, StateTrue, Pred, tags.first)); + Bldr.generateNode(Ex, Pred, StateTrue, false, tags.first); } // Next, assume that the condition is false. if (const ProgramState *StateFalse = state->assume(*SEV, false)) { SVal Val = svalBuilder.makeIntVal(0U, Ex->getType()); StateFalse = StateFalse->BindExpr(Ex, Val); - Dst.Add(Builder->generateNode(Ex, StateFalse, Pred, tags.second)); + Bldr.generateNode(Ex, Pred, StateFalse, false, tags.second); } } - else - Dst.Add(Pred); } } @@ -1625,7 +1744,7 @@ void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt *A, ExplodedNode *Pred, ExplodedNodeSet &Dst) { if (I == E) { - + PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); // We have processed both the inputs and the outputs. All of the outputs // should evaluate to Locs. Nuke all of their values. @@ -1645,7 +1764,7 @@ void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt *A, state = state->bindLoc(cast<Loc>(X), UnknownVal()); } - MakeNode(Dst, A, Pred, state); + Bldr.generateNode(A, Pred, state); return; } diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index b70a5f1e14..a91439afea 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -46,7 +46,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // FIXME: Handle structs. if (RightV.isUnknown() || !getConstraintManager().canReasonAbout(RightV)) { - unsigned Count = Builder->getCurrentBlockCount(); + unsigned Count = currentBuilderContext->getCurrentBlockCount(); RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), Count); } // Simulate the effects of a "store": bind the value of the RHS @@ -57,16 +57,17 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, } if (!B->isAssignmentOp()) { + PureStmtNodeBuilder Bldr(*it, Tmp2, *currentBuilderContext, Builder); // Process non-assignments except commas or short-circuited // logical expressions (LAnd and LOr). SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType()); if (Result.isUnknown()) { - MakeNode(Tmp2, B, *it, state); + Bldr.generateNode(B, *it, state); continue; } state = state->BindExpr(B, Result); - MakeNode(Tmp2, B, *it, state); + Bldr.generateNode(B, *it, state); continue; } @@ -125,7 +126,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)) { - unsigned Count = Builder->getCurrentBlockCount(); + unsigned Count = currentBuilderContext->getCurrentBlockCount(); // The symbolic value is actually for the type of the left-hand side // expression, not the computation type, as this is the value the @@ -165,8 +166,9 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, Pred->getLocationContext()); ExplodedNodeSet Tmp; - MakeNode(Tmp, BE, Pred, Pred->getState()->BindExpr(BE, V), - ProgramPoint::PostLValueKind); + PureStmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext); + Bldr.generateNode(BE, Pred, Pred->getState()->BindExpr(BE, V), false, 0, + ProgramPoint::PostLValueKind); // FIXME: Move all post/pre visits to ::Visit(). getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this); @@ -196,6 +198,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE)) T = ExCast->getTypeAsWritten(); + PureStmtNodeBuilder Bldr(dstPreStmt, Dst, *currentBuilderContext, Builder); for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); I != E; ++I) { @@ -207,7 +210,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_GetObjCProperty: llvm_unreachable("GetObjCProperty casts handled earlier."); case CK_ToVoid: - Dst.Add(Pred); continue; // The analyzer doesn't do anything special with these casts, // since it understands retain/release semantics already. @@ -222,7 +224,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, const ProgramState *state = Pred->getState(); SVal V = state->getSVal(Ex); state = state->BindExpr(CastE, V); - MakeNode(Dst, CastE, Pred, state); + Bldr.generateNode(CastE, Pred, state); continue; } case CK_Dependent: @@ -258,7 +260,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, SVal V = state->getSVal(Ex); V = svalBuilder.evalCast(V, T, ExTy); state = state->BindExpr(CastE, V); - MakeNode(Dst, CastE, Pred, state); + Bldr.generateNode(CastE, Pred, state); continue; } case CK_DerivedToBase: @@ -268,7 +270,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, SVal val = state->getSVal(Ex); val = getStoreManager().evalDerivedToBase(val, T); state = state->BindExpr(CastE, val); - MakeNode(Dst, CastE, Pred, state); + Bldr.generateNode(CastE, Pred, state); continue; } // Various C++ casts that are not handled yet. @@ -289,10 +291,10 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, SVal result = svalBuilder.getConjuredSymbolVal(NULL, CastE, resultType, - Builder->getCurrentBlockCount()); + currentBuilderContext->getCurrentBlockCount()); const ProgramState *state = Pred->getState()->BindExpr(CastE, result); - MakeNode(Dst, CastE, Pred, state); + Bldr.generateNode(CastE, Pred, state); continue; } } @@ -302,8 +304,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext); - Builder->takeNodes(Pred); + PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext, Builder); const InitListExpr *ILE = cast<InitListExpr>(CL->getInitializer()->IgnoreParens()); @@ -317,7 +318,6 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, B.generateNode(CL, Pred, state->BindExpr(CL, state->getLValue(CL, LC))); else B.generateNode(CL, Pred, state->BindExpr(CL, ILV)); - Builder->addNodes(Dst); } void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, @@ -330,15 +330,17 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, // Assumption: The CFG has one DeclStmt per Decl. const Decl *D = *DS->decl_begin(); - if (!D || !isa<VarDecl>(D)) + if (!D || !isa<VarDecl>(D)) { + //TODO:AZ: remove explicit insertion after refactoring is done. + Dst.insert(Pred); return; + } // FIXME: all pre/post visits should eventually be handled by ::Visit(). ExplodedNodeSet dstPreVisit; getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this); - PureStmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext); - Builder->takeNodes(dstPreVisit); + PureStmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext, Builder); const VarDecl *VD = dyn_cast<VarDecl>(D); for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end(); I!=E; ++I) { @@ -365,7 +367,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, !getConstraintManager().canReasonAbout(InitVal)) && !VD->getType()->isReferenceType()) { InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, - Builder->getCurrentBlockCount()); + currentBuilderContext->getCurrentBlockCount()); } B.takeNodes(N); evalBind(Dst, DS, N, state->getLValue(VD, LC), InitVal, true); @@ -375,17 +377,14 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, B.generateNode(DS, N,state->bindDeclWithNoInit(state->getRegion(VD, LC))); } } - Builder->addNodes(Dst); } void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - Builder->takeNodes(Pred); - PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); - assert(B->getOpcode() == BO_LAnd || B->getOpcode() == BO_LOr); - + + PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); const ProgramState *state = Pred->getState(); SVal X = state->getSVal(B); assert(X.isUndef()); @@ -399,7 +398,6 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, // Handle undefined values. if (X.isUndef()) { Bldr.generateNode(B, Pred, state->BindExpr(B, X)); - Builder->addNodes(Dst); return; } @@ -427,14 +425,12 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, B->getType()); Bldr.generateNode(B, Pred, state->BindExpr(B, X)); } - Builder->addNodes(Dst); } void ExprEngine::VisitInitListExpr(const InitListExpr *IE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - Builder->takeNodes(Pred); - PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext); + PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext, Builder); const ProgramState *state = Pred->getState(); QualType T = getContext().getCanonicalType(IE->getType()); @@ -448,7 +444,6 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE, if (NumInitElements == 0) { SVal V = svalBuilder.makeCompoundVal(T, vals); B.generateNode(IE, Pred, state->BindExpr(IE, V)); - Builder->addNodes(Dst); return; } @@ -459,7 +454,6 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE, B.generateNode(IE, Pred, state->BindExpr(IE, svalBuilder.makeCompoundVal(T, vals))); - Builder->addNodes(Dst); return; } @@ -467,7 +461,6 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE, assert(IE->getNumInits() == 1); const Expr *initEx = IE->getInit(0); B.generateNode(IE, Pred, state->BindExpr(IE, state->getSVal(initEx))); - Builder->addNodes(Dst); return; } @@ -479,8 +472,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, const Expr *R, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - Builder->takeNodes(Pred); - PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext); + PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext, Builder); const ProgramState *state = Pred->getState(); SVal X = state->getSVal(Ex); @@ -491,14 +483,12 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, // Make sure that we invalidate the previous binding. B.generateNode(Ex, Pred, state->BindExpr(Ex, X, true)); - Builder->addNodes(Dst); } void ExprEngine:: VisitOffsetOfExpr(const OffsetOfExpr *OOE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - Builder->takeNodes(Pred); - PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext); + PureStmtNodeBuilder B(Pred, Dst, *currentBuilderContext, Builder); Expr::EvalResult Res; if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) { const APSInt &IV = Res.Val.getInt(); @@ -509,7 +499,6 @@ VisitOffsetOfExpr(const OffsetOfExpr *OOE, B.generateNode(OOE, Pred, Pred->getState()->BindExpr(OOE, X)); } // FIXME: Handle the case where __builtin_offsetof is not a constant. - Builder->addNodes(Dst); } @@ -517,6 +506,7 @@ void ExprEngine:: VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); QualType T = Ex->getTypeOfArgument(); @@ -526,14 +516,12 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, // FIXME: Add support for VLA type arguments and VLA expressions. // When that happens, we should probably refactor VLASizeChecker's code. - Dst.Add(Pred); return; } else if (T->getAs<ObjCObjectType>()) { // Some code tries to take the sizeof an ObjCObjectType, relying that // the compiler has laid out its representation. Just report Unknown // for these. - Dst.Add(Pred); return; } } @@ -545,20 +533,22 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, const ProgramState *state = Pred->getState(); state = state->BindExpr(Ex, svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType())); - MakeNode(Dst, Ex, Pred, state); + Bldr.generateNode(Ex, Pred, state); } void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - Builder->takeNodes(Pred); PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); bool IncDec = false; switch (U->getOpcode()) { - default: - Builder->addNodes(Pred); + default: { + Bldr.takeNodes(Pred); IncDec = true; - VisitIncrementDecrementOperator(U, Pred, Dst); + ExplodedNodeSet Tmp; + VisitIncrementDecrementOperator(U, Pred, Tmp); + Bldr.addNodes(Tmp); + } break; case UO_Real: { const Expr *Ex = U->getSubExpr()->IgnoreParens(); @@ -690,8 +680,6 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, } } - if (!IncDec) - Builder->addNodes(Dst); } void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, @@ -712,6 +700,8 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, ExplodedNodeSet Tmp2; evalLoad(Tmp2, Ex, *I, state, loc); + ExplodedNodeSet Dst2; + PureStmtNodeBuilder Bldr(Tmp2, Dst2, *currentBuilderContext, Builder); for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) { state = (*I2)->getState(); @@ -719,7 +709,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, // Propagate unknown and undefined values. if (V2_untested.isUnknownOrUndef()) { - MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested)); + Bldr.generateNode(U, *I2, state->BindExpr(U, V2_untested)); continue; } DefinedSVal V2 = cast<DefinedSVal>(V2_untested); @@ -744,7 +734,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){ DefinedOrUnknownSVal SymVal = svalBuilder.getConjuredSymbolVal(NULL, Ex, - Builder->getCurrentBlockCount()); + currentBuilderContext->getCurrentBlockCount()); Result = SymVal; // If the value is a location, ++/-- should always preserve @@ -775,7 +765,11 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, state = state->BindExpr(U, U->isPostfix() ? V2 : Result); // Perform the store. - evalStore(Dst, NULL, U, *I2, state, loc, Result); + Bldr.takeNodes(*I2); + ExplodedNodeSet Dst4; + evalStore(Dst4, NULL, U, *I2, state, loc, Result); + Bldr.addNodes(Dst4); } + Dst.insert(Dst2); } } diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index e9d5e2cc6d..1d14735ae7 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -107,6 +107,7 @@ const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXMethodDecl *decl, void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens(); const ProgramState *state = Pred->getState(); @@ -119,7 +120,7 @@ void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, Pred->getLocationContext()); state = state->bindLoc(loc::MemRegionVal(R), V); - MakeNode(Dst, ME, Pred, state->BindExpr(ME, loc::MemRegionVal(R))); + Bldr.generateNode(ME, Pred, state->BindExpr(ME, loc::MemRegionVal(R))); } void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, @@ -174,7 +175,8 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, // parameter region. const StackFrameContext *SFC = AMgr.getStackFrame(CD, Pred->getLocationContext(), - E, Builder->getBlock(), Builder->getIndex()); + E, currentBuilderContext->getBlock(), + currentStmtIdx); // Create the 'this' region. const CXXThisRegion *ThisR = @@ -182,43 +184,45 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, CallEnter Loc(E, SFC, Pred->getLocationContext()); - + PureStmtNodeBuilder Bldr(argsEvaluated, destNodes, *currentBuilderContext); for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(), NE = argsEvaluated.end(); NI != NE; ++NI) { const ProgramState *state = (*NI)->getState(); // Setup 'this' region, so that the ctor is evaluated on the object pointed // by 'Dest'. state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); - if (ExplodedNode *N = Builder->generateNode(Loc, state, *NI)) - destNodes.Add(N); + Bldr.generateNode(Loc, *NI, state); } } #endif // Default semantics: invalidate all regions passed as arguments. ExplodedNodeSet destCall; - - for (ExplodedNodeSet::iterator - i = destPreVisit.begin(), e = destPreVisit.end(); - i != e; ++i) { - ExplodedNode *Pred = *i; - const LocationContext *LC = Pred->getLocationContext(); - const ProgramState *state = Pred->getState(); + PureStmtNodeBuilder Bldr(destPreVisit, destCall, + *currentBuilderContext, Builder); + for (ExplodedNodeSet::iterator + i = destPreVisit.begin(), e = destPreVisit.end(); + i != e; ++i) + { + ExplodedNode *Pred = *i; + const LocationContext *LC = Pred->getLocationContext(); + const ProgramState *state = Pred->getState(); - state = invalidateArguments(state, CallOrObjCMessage(E, state), LC); - Builder->MakeNode(destCall, E, Pred, state); + state = invalidateArguments(state, CallOrObjCMessage(E, state), LC); + Bldr.generateNode(E, Pred, state); + } } - // Do the post visit. getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this); } void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, - const MemRegion *Dest, - const Stmt *S, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { + const MemRegion *Dest, + const Stmt *S, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); if (!(DD->doesThisDeclarationHaveABody() && AMgr.shouldInlineCall())) return; @@ -226,7 +230,7 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, const StackFrameContext *SFC = AnalysisDeclContexts.getContext(DD)-> getStackFrame(Pred->getLocationContext(), S, - Builder->getBlock(), Builder->getIndex()); + currentBuilderContext->getBlock(), currentStmtIdx); const CXXThisRegion *ThisR = getCXXThisRegion(DD->getParent(), SFC); @@ -234,15 +238,14 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, const ProgramState *state = Pred->getState(); state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); - ExplodedNode *N = Builder->generateNode(PP, state, Pred); - if (N) - Dst.Add(N); + Bldr.generateNode(PP, Pred, state); } void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); - unsigned blockCount = Builder->getCurrentBlockCount(); + unsigned blockCount = currentBuilderContext->getCurrentBlockCount(); DefinedOrUnknownSVal symVal = svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), blockCount); const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion(); @@ -255,7 +258,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // For now, just return a symbolicated region. const ProgramState *state = Pred->getState(); state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); - MakeNode(Dst, CNE, Pred, state); + Bldr.generateNode(CNE, Pred, state); return; } @@ -265,8 +268,10 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, if (CD) FnType = CD->getType()->getAs<FunctionProtoType>(); ExplodedNodeSet argsEvaluated; + Bldr.takeNodes(Pred); evalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(), FnType, Pred, argsEvaluated); + Bldr.addNodes(argsEvaluated); // Initialize the object region and bind the 'new' expression. for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), @@ -310,24 +315,27 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, } } state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); - MakeNode(Dst, CNE, *I, state); + Bldr.generateNode(CNE, *I, state); } } void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, - ExplodedNode *Pred,ExplodedNodeSet &Dst) { + ExplodedNode *Pred, ExplodedNodeSet &Dst) { // Should do more checking. ExplodedNodeSet Argevaluated; Visit(CDE->getArgument(), Pred, Argevaluated); + PureStmtNodeBuilder Bldr(Argevaluated, Dst, *currentBuilderContext, Builder); for (ExplodedNodeSet::iterator I = Argevaluated.begin(), E = Argevaluated.end(); I != E; ++I) { const ProgramState *state = (*I)->getState(); - MakeNode(Dst, CDE, *I, state); + Bldr.generateNode(CDE, *I, state); } } void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { + PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext, Builder); + // Get the this object region from StoreManager. const MemRegion *R = svalBuilder.getRegionManager().getCXXThisRegion( @@ -336,5 +344,5 @@ void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, const ProgramState *state = Pred->getState(); SVal V = state->getSVal(loc::MemRegionVal(R)); - MakeNode(Dst, TE, Pred, state->BindExpr(TE, V)); + Bldr.generateNode(TE, Pred, state->BindExpr(TE, V)); } diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 6d377b9591..b804a40f74 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -147,7 +147,7 @@ ExprEngine::invalidateArguments(const ProgramState *State, // expression (the context) and the expression itself. This should // disambiguate conjured symbols. assert(Builder && "Invalidating arguments outside of a statement context"); - unsigned Count = Builder->getCurrentBlockCount(); + unsigned Count = currentBuilderContext->getCurrentBlockCount(); StoreManager::InvalidatedSymbols IS; // NOTE: Even if RegionsToInvalidate is empty, we may still invalidate @@ -180,8 +180,7 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, } // First handle the return value. - StmtNodeBuilder &Builder = Eng.getBuilder(); - assert(&Builder && "StmtNodeBuilder must be defined."); + PureStmtNodeBuilder Bldr(Pred, Dst, *Eng.currentBuilderContext, Eng.Builder); // Get the callee. const Expr *Callee = CE->getCallee()->IgnoreParens(); @@ -200,7 +199,7 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, // Conjure a symbol value to use as the result. SValBuilder &SVB = Eng.getSValBuilder(); - unsigned Count = Builder.getCurrentBlockCount(); + unsigned Count = Eng.currentBuilderContext->getCurrentBlockCount(); SVal RetVal = SVB.getConjuredSymbolVal(0, CE, ResultTy, Count); // Generate a new state with the return value set. @@ -211,7 +210,7 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, state = Eng.invalidateArguments(state, CallOrObjCMessage(CE, state), LC); // And make the result node. - Eng.MakeNode(Dst, CE, Pred, state); + Bldr.generateNode(CE, Pred, state); } }; @@ -232,21 +231,25 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNodeSet Src; - if (const Expr *RetE = RS->getRetValue()) { - // Record the returned expression in the state. It will be used in - // processCallExit to bind the return value to the call expr. - { - static SimpleProgramPointTag tag("ExprEngine: ReturnStmt"); - const ProgramState *state = Pred->getState(); - state = state->set<ReturnExpr>(RetE); - Pred = Builder->generateNode(RetE, state, Pred, &tag); + { + PureStmtNodeBuilder Bldr(Pred, Src, *currentBuilderContext, Builder); + if (const Expr *RetE = RS->getRetValue()) { + // Record the returned expression in the state. It will be used in + // processCallExit to bind the return value to the call expr. + { + static SimpleProgramPointTag tag("ExprEngine: ReturnStmt"); + const ProgramState *state = Pred->getState(); + state = state->set<ReturnExpr>(RetE); + Pred = Bldr.generateNode(RetE, Pred, state, false, &tag); + } + // We may get a NULL Pred because we generated a cached node. + if (Pred) { + Bldr.takeNodes(Pred); + ExplodedNodeSet Tmp; + Visit(RetE, Pred, Tmp); + Bldr.addNodes(Tmp); + } } - // We may get a NULL Pred because we generated a cached node. - if (Pred) - Visit(RetE, Pred, Src); - } - else { - Src.Add(Pred); } getCheckerManager().runCheckersForPreStmt(Dst, Src, RS, *this); diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp index 7827873e9d..a3280ab774 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp @@ -14,7 +14,6 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h" -#include "clang/Analysis/Support/SaveAndRestore.h" using namespace clang; using namespace ento; @@ -22,13 +21,13 @@ using namespace ento; void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - const ProgramState *state = Pred->getState(); SVal baseVal = state->getSVal(Ex->getBase()); SVal location = state->getLValue(Ex->getDecl(), baseVal); ExplodedNodeSet dstIvar; - MakeNode(dstIvar, Ex, Pred, state->BindExpr(Ex, location)); + PureStmtNodeBuilder Bldr(Pred, dstIvar, *currentBuilderContext); + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, location)); // Perform the post-condition check of the ObjCIvarRefExpr and store // the created nodes in 'Dst'. @@ -69,10 +68,11 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, // For now: simulate (1) by assigning either a symbol or nil if the // container is empty. Thus this transfer function will by default // result in state splitting. - + const Stmt *elem = S->getElement(); const ProgramState *state = Pred->getState(); SVal elementV; + PureStmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) { const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl()); @@ -84,10 +84,9 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, } ExplodedNodeSet dstLocation; + Bldr.takeNodes(Pred); evalLocation(dstLocation, elem, Pred, state, elementV, NULL, false); - - if (dstLocation.empty()) - return; + Bldr.addNodes(dstLocation); for (ExplodedNodeSet::iterator NI = dstLocation.begin(), NE = dstLocation.end(); NI!=NE; ++NI) { @@ -110,7 +109,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, // For now, just 'conjure' up a symbolic value. QualType T = R->getValueType(); assert(Loc::isLocType(T)); - unsigned Count = Builder->getCurrentBlockCount(); + unsigned Count = currentBuilderContext->getCurrentBlockCount(); SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count); SVal V = svalBuilder.makeLoc(Sym); hasElems = hasElems->bindLoc(elementV, V); @@ -121,8 +120,8 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, } // Create the new nodes. - MakeNode(Dst, S, Pred, hasElems); - MakeNode(Dst, S, Pred, noElems); + Bldr.generateNode(S, Pred, hasElems); + Bldr.generateNode(S, Pred, noElems); } } @@ -137,14 +136,13 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, // Proceed with evaluate the message expression. ExplodedNodeSet dstEval; - + PureStmtNodeBuilder Bldr(dstPrevisit, dstEval, *currentBuilderContext); + for (ExplodedNodeSet::iterator DI = dstPrevisit.begin(), DE = dstPrevisit.end(); DI != DE; ++DI) { ExplodedNode *Pred = *DI; bool RaisesException = false; - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - SaveOr OldHasGen(Builder->hasGeneratedNode); if (const Expr *Receiver = msg.getInstanceReceiver()) { const ProgramState *state = Pred->getState(); @@ -159,7 +157,6 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, // There are three cases: can be nil or non-nil, must be nil, must be // non-nil. We ignore must be nil, and merge the rest two into non-nil. if (nilState && !notNilState) { - dstEval.insert(Pred); continue; } @@ -168,13 +165,10 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, if (msg.getSelector() == RaiseSel) RaisesException = true; - // Check if we raise an exception. For now treat these as sinks. + // If we raise an exception, for now treat it as a sink. // Eventually we will want to handle exceptions properly. - if (RaisesException) - Builder->BuildSinks = true; - // Dispatch to plug-in transfer function. - evalObjCMessage(dstEval, msg, Pred, notNilState); + evalObjCMessage(Bldr, msg, Pred, notNilState, RaisesException); } } else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) { @@ -217,16 +211,11 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, } } - // Check if we raise an exception. For now treat these as sinks. + // If we raise an exception, for now treat it as a sink. // Eventually we will want to handle exceptions properly. - if (RaisesException) - Builder->BuildSinks = true; - // Dispatch to plug-in transfer function. - evalObjCMessage(dstEval, msg, Pred, Pred->getState()); + evalObjCMessage(Bldr, msg, Pred, Pred->getState(), RaisesException); } - - assert(Builder->BuildSinks || Builder->hasGeneratedNodes()); } // Finally, perform the post-condition check of the ObjCMessageExpr and store @@ -234,11 +223,11 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this); } -void ExprEngine::evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg, +void ExprEngine::evalObjCMessage(PureStmtNodeBuilder &Bldr, + const ObjCMessage &msg, ExplodedNode *Pred, - const ProgramState *state) { - assert (Builder && "StmtNodeBuilder must be defined."); - + const ProgramState *state, + bool GenSink) { // First handle the return value. SVal ReturnValue = UnknownVal(); @@ -261,7 +250,7 @@ void ExprEngine::evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg, if (ReturnValue.isUnknown()) { SValBuilder &SVB = getSValBuilder(); QualType ResultTy = msg.getResultType(getContext()); - unsigned Count = Builder->getCurrentBlockCount(); + unsigned Count = currentBuilderContext->getCurrentBlockCount(); const Expr *CurrentE = cast<Expr>(currentStmt); ReturnValue = SVB.getConjuredSymbolVal(NULL, CurrentE, ResultTy, Count); } @@ -274,6 +263,7 @@ void ExprEngine::evalObjCMessage(ExplodedNodeSet &Dst, const ObjCMessage &msg, state = invalidateArguments(state, CallOrObjCMessage(msg, state), LC); // And create the new node. - MakeNode(Dst, msg.getOriginExpr(), Pred, state); + Bldr.generateNode(msg.getOriginExpr(), Pred, state, GenSink); + assert(Bldr.hasGeneratedNodes()); } |