From ebae6d0209e1ec3d5ea14f9e63bd0d740218ed14 Mon Sep 17 00:00:00 2001 From: Anna Zaks Date: Mon, 24 Oct 2011 18:26:19 +0000 Subject: [PATCH] [analyzer] Convert ExprEngine::visit() to use short lived builders. This commit removes the major functional dependency on the ExprEngine::Builder member variable. In some cases the code became more verbose. Particularly, we call takeNodes() and addNodes() to move responsibility for the nodes from one builder to another. This will get simplified later on. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142831 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../StaticAnalyzer/Core/CheckerManager.h | 4 +- .../Core/PathSensitive/CheckerContext.h | 4 +- .../Core/PathSensitive/CoreEngine.h | 69 ++-- .../Core/PathSensitive/ExprEngine.h | 29 +- .../Core/PathSensitive/SubEngine.h | 4 +- lib/StaticAnalyzer/Core/CheckerManager.cpp | 15 +- lib/StaticAnalyzer/Core/CoreEngine.cpp | 14 +- lib/StaticAnalyzer/Core/ExprEngine.cpp | 305 ++++++++++++------ lib/StaticAnalyzer/Core/ExprEngineC.cpp | 92 +++--- lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 66 ++-- .../Core/ExprEngineCallAndReturn.cpp | 41 +-- 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 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 > @@ -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(E.getAs()->getStmt()), Bldr, Pred); + ProcessStmt(const_cast(E.getAs()->getStmt()), Pred); return; case CFGElement::Initializer: - ProcessInitializer(E.getAs()->getInitializer(), - Bldr, Pred); + ProcessInitializer(E.getAs()->getInitializer(), Pred); return; case CFGElement::AutomaticObjectDtor: case CFGElement::BaseDtor: case CFGElement::MemberDtor: case CFGElement::TemporaryDtor: - ProcessImplicitDtor(*E.getAs(), Bldr, Pred); + ProcessImplicitDtor(*E.getAs(), Pred); return; } } -void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder, +const Stmt *ExprEngine::getStmt() const { + const CFGStmt *CS = (*currentBuilderContext->getBlock())[currentStmtIdx].getAs(); + 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(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(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 OldSink(Builder->BuildSinks); - SaveOr OldHasGen(Builder->hasGeneratedNode); + SaveAndRestore OldSink(builder.BuildSinks); + SaveOr OldHasGen(builder.hasGeneratedNode); - SaveAndRestore OldPurgeDeadSymbols(Builder->PurgingDeadSymbols); - Builder->PurgingDeadSymbols = true; + SaveAndRestore 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(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(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 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(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(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(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(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::AsmStmtClass: + Bldr.takeNodes(Pred); VisitAsmStmt(cast(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::BlockDeclRefExprClass: { + Bldr.takeNodes(Pred); const BlockDeclRefExpr *BE = cast(S); VisitCommonDeclRefExpr(BE, BE->getDecl(), Pred, Dst); + Bldr.addNodes(Dst); break; } case Stmt::BlockExprClass: + Bldr.takeNodes(Pred); VisitBlockExpr(cast(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::BinaryOperatorClass: { const BinaryOperator* B = cast(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(S), Pred, Dst); + Bldr.addNodes(Dst); break; } case Stmt::CallExprClass: case Stmt::CXXOperatorCallExprClass: case Stmt::CXXMemberCallExprClass: { + Bldr.takeNodes(Pred); VisitCallExpr(cast(S), Pred, Dst); + Bldr.addNodes(Dst); break; } @@ -640,58 +716,78 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, const CXXConstructExpr *C = cast(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(S); VisitCXXNewExpr(NE, Pred, Dst); + Bldr.addNodes(Dst); break; } case Stmt::CXXDeleteExprClass: { + Bldr.takeNodes(Pred); const CXXDeleteExpr *CDE = cast(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(S); VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst); + Bldr.addNodes(Dst); break; } case Stmt::CompoundAssignOperatorClass: + Bldr.takeNodes(Pred); VisitBinaryOperator(cast(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::CompoundLiteralExprClass: + Bldr.takeNodes(Pred); VisitCompoundLiteralExpr(cast(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: { // '?' operator + Bldr.takeNodes(Pred); const AbstractConditionalOperator *C = cast(S); VisitGuardedExpr(C, C->getTrueExpr(), C->getFalseExpr(), Pred, Dst); + Bldr.addNodes(Dst); break; } case Stmt::CXXThisExprClass: + Bldr.takeNodes(Pred); VisitCXXThisExpr(cast(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::DeclRefExprClass: { + Bldr.takeNodes(Pred); const DeclRefExpr *DE = cast(S); VisitCommonDeclRefExpr(DE, DE->getDecl(), Pred, Dst); + Bldr.addNodes(Dst); break; } case Stmt::DeclStmtClass: + Bldr.takeNodes(Pred); VisitDeclStmt(cast(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(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(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(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::MemberExprClass: + Bldr.takeNodes(Pred); VisitMemberExpr(cast(S), Pred, Dst); + Bldr.addNodes(Dst); break; + case Stmt::ObjCIvarRefExprClass: + Bldr.takeNodes(Pred); VisitLvalObjCIvarRefExpr(cast(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::ObjCForCollectionStmtClass: + Bldr.takeNodes(Pred); VisitObjCForCollectionStmt(cast(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::ObjCMessageExprClass: + Bldr.takeNodes(Pred); VisitObjCMessage(cast(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::ObjCAtThrowStmtClass: { // FIXME: This is not complete. We basically treat @throw as // an abort. - SaveAndRestore 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(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::OffsetOfExprClass: + Bldr.takeNodes(Pred); VisitOffsetOfExpr(cast(S), Pred, Dst); + Bldr.addNodes(Dst); break; case Stmt::UnaryExprOrTypeTraitExprClass: + Bldr.takeNodes(Pred); VisitUnaryExprOrTypeTraitExpr(cast(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(*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(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(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(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(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(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(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(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 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 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(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(P) || cast(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(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(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(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(D)) + if (!D || !isa(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(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()) { // 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(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(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(); 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(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(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(elem)) { const VarDecl *elemD = cast(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 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(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()); } -- 2.40.0