diff options
-rw-r--r-- | include/clang/Analysis/PathSensitive/GRCoreEngine.h | 71 | ||||
-rw-r--r-- | include/clang/Analysis/ProgramPoint.h | 18 | ||||
-rw-r--r-- | lib/Analysis/BugReporter.cpp | 97 | ||||
-rw-r--r-- | lib/Analysis/GRCoreEngine.cpp | 22 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 14 |
5 files changed, 159 insertions, 63 deletions
diff --git a/include/clang/Analysis/PathSensitive/GRCoreEngine.h b/include/clang/Analysis/PathSensitive/GRCoreEngine.h index aa8ca231b0..5cb4fd7d52 100644 --- a/include/clang/Analysis/PathSensitive/GRCoreEngine.h +++ b/include/clang/Analysis/PathSensitive/GRCoreEngine.h @@ -149,20 +149,25 @@ public: unsigned getCurrentBlockCount() const { return getBlockCounter().getNumVisited(B.getBlockID()); } - - ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State, - ExplodedNodeImpl* Pred, - bool isLoad = false); + + ExplodedNodeImpl* + generateNodeImpl(Stmt* S, void* State, ExplodedNodeImpl* Pred, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind); - inline ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State, - bool isLoad = false) { + ExplodedNodeImpl* + generateNodeImpl(Stmt* S, void* State, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind) { ExplodedNodeImpl* N = getLastNode(); assert (N && "Predecessor of new node is infeasible."); - return generateNodeImpl(S, State, N, isLoad); + return generateNodeImpl(S, State, N, K); } + /// getStmt - Return the current block-level expression associated with + /// this builder. Stmt* getStmt() const { return B[Idx]; } + /// getBlock - Return the CFGBlock associated with the block-level expression + /// of this builder. CFGBlock* getBlock() const { return &B; } }; @@ -182,6 +187,7 @@ public: GRStmtNodeBuilder(GRStmtNodeBuilderImpl& nb) : NB(nb), CallExprAuditBeg(0), CallExprAuditEnd(0), ObjCMsgExprAuditBeg(0), ObjCMsgExprAuditEnd(0), + PurgingDeadSymbols(false), BuildSinks(false), HasGeneratedNode(false) { CleanedState = getLastNode()->getState(); @@ -203,14 +209,22 @@ public: return static_cast<NodeTy*>(NB.getLastNode()); } - NodeTy* generateNode(Stmt* S, StateTy* St, NodeTy* Pred, bool isLoad = false){ + NodeTy* + generateNode(Stmt* S, StateTy* St, NodeTy* Pred, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind) { + HasGeneratedNode = true; - return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, isLoad)); + if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind; + return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, K)); } - NodeTy* generateNode(Stmt* S, StateTy* St, bool isLoad = false) { + NodeTy* + generateNode(Stmt* S, StateTy* St, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind) { + HasGeneratedNode = true; - return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, isLoad)); + if (PurgingDeadSymbols) K = ProgramPoint::PostPurgeDeadSymbolsKind; + return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, K)); } GRBlockCounter getBlockCounter() const { @@ -274,6 +288,7 @@ public: return N; } + bool PurgingDeadSymbols; bool BuildSinks; bool HasGeneratedNode; }; @@ -338,7 +353,7 @@ public: return getPredecessor()->getState(); } - inline NodeTy* generateNode(StateTy* St, bool branch) { + NodeTy* generateNode(StateTy* St, bool branch) { return static_cast<NodeTy*>(NB.generateNodeImpl(St, branch)); } @@ -350,7 +365,7 @@ public: return NB.getTargetBlock(branch); } - inline void markInfeasible(bool branch) { + void markInfeasible(bool branch) { NB.markInfeasible(branch); } }; @@ -393,8 +408,8 @@ public: ExplodedNodeImpl* generateNodeImpl(const Iterator& I, void* State, bool isSink); - inline Expr* getTarget() const { return E; } - inline void* getState() const { return Pred->State; } + Expr* getTarget() const { return E; } + void* getState() const { return Pred->State; } }; template<typename STATE> @@ -410,16 +425,16 @@ public: typedef GRIndirectGotoNodeBuilderImpl::Iterator iterator; - inline iterator begin() { return NB.begin(); } - inline iterator end() { return NB.end(); } + iterator begin() { return NB.begin(); } + iterator end() { return NB.end(); } - inline Expr* getTarget() const { return NB.getTarget(); } + Expr* getTarget() const { return NB.getTarget(); } - inline NodeTy* generateNode(const iterator& I, StateTy* St, bool isSink=false){ + NodeTy* generateNode(const iterator& I, StateTy* St, bool isSink=false){ return static_cast<NodeTy*>(NB.generateNodeImpl(I, St, isSink)); } - inline StateTy* getState() const { + StateTy* getState() const { return static_cast<StateTy*>(NB.getState()); } }; @@ -459,8 +474,8 @@ public: ExplodedNodeImpl* generateCaseStmtNodeImpl(const Iterator& I, void* State); ExplodedNodeImpl* generateDefaultCaseNodeImpl(void* State, bool isSink); - inline Expr* getCondition() const { return Condition; } - inline void* getState() const { return Pred->State; } + Expr* getCondition() const { return Condition; } + void* getState() const { return Pred->State; } }; template<typename STATE> @@ -476,20 +491,20 @@ public: typedef GRSwitchNodeBuilderImpl::Iterator iterator; - inline iterator begin() { return NB.begin(); } - inline iterator end() { return NB.end(); } + iterator begin() { return NB.begin(); } + iterator end() { return NB.end(); } - inline Expr* getCondition() const { return NB.getCondition(); } + Expr* getCondition() const { return NB.getCondition(); } - inline NodeTy* generateCaseStmtNode(const iterator& I, StateTy* St) { + NodeTy* generateCaseStmtNode(const iterator& I, StateTy* St) { return static_cast<NodeTy*>(NB.generateCaseStmtNodeImpl(I, St)); } - inline NodeTy* generateDefaultCaseNode(StateTy* St, bool isSink = false) { + NodeTy* generateDefaultCaseNode(StateTy* St, bool isSink = false) { return static_cast<NodeTy*>(NB.generateDefaultCaseNodeImpl(St, isSink)); } - inline StateTy* getState() const { + StateTy* getState() const { return static_cast<StateTy*>(NB.getState()); } }; diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h index efd16b416d..ecb4f742c7 100644 --- a/include/clang/Analysis/ProgramPoint.h +++ b/include/clang/Analysis/ProgramPoint.h @@ -25,9 +25,10 @@ namespace clang { class ProgramPoint { public: - enum Kind { BlockEntranceKind=0, PostStmtKind=1, PostLoadKind=2, - BlockExitKind=3, BlockEdgeSrcKind=4, BlockEdgeDstKind=5, - BlockEdgeAuxKind=6 }; + enum Kind { BlockEntranceKind=0, + PostStmtKind=1, PostLoadKind=2, PostPurgeDeadSymbolsKind=3, + BlockExitKind=4, BlockEdgeSrcKind=5, BlockEdgeDstKind=6, + BlockEdgeAuxKind=7 }; protected: uintptr_t Data; @@ -110,7 +111,7 @@ public: static bool classof(const ProgramPoint* Location) { unsigned k = Location->getKind(); - return k == PostStmtKind || k == PostLoadKind; + return k >= PostStmtKind && k <= PostPurgeDeadSymbolsKind; } }; @@ -123,6 +124,15 @@ public: } }; +class PostPurgeDeadSymbols : public PostStmt { +public: + PostPurgeDeadSymbols(const Stmt* S) : PostStmt(S, PostPurgeDeadSymbolsKind) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostPurgeDeadSymbolsKind; + } +}; + class BlockEdge : public ProgramPoint { typedef std::pair<CFGBlock*,CFGBlock*> BPair; public: diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp index 141ee48aa0..240ecd19fe 100644 --- a/lib/Analysis/BugReporter.cpp +++ b/lib/Analysis/BugReporter.cpp @@ -21,7 +21,7 @@ #include "clang/AST/Expr.h" #include "clang/Analysis/ProgramPoint.h" #include "clang/Analysis/PathDiagnostic.h" -#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/DenseMap.h" #include <sstream> using namespace clang; @@ -204,43 +204,86 @@ MakeReportGraph(ExplodedGraph<ValueState>* G, ExplodedNode<ValueState>* N) { G = new ExplodedGraph<ValueState>(GTrim->getCFG(), GTrim->getCodeDecl(), GTrim->getContext()); - - ExplodedNode<ValueState> *Last = 0, *First = 0; - - // Sometimes TrimGraph can contain a cycle because there are multiple BFS - // paths with the same length. We mark the nodes we visit so that we - // don't get stuck in a cycle. - llvm::DenseSet<void*> Visited; + // Sometimes TrimGraph can contain a cycle. Perform a reverse DFS + // to the root node, and then construct a new graph that contains only + // a single path. + llvm::DenseMap<void*,unsigned> Visited; + llvm::SmallVector<ExplodedNode<ValueState>*, 10> WS; + WS.push_back(N); + unsigned cnt = 0; + ExplodedNode<ValueState>* Root = 0; + + while (!WS.empty()) { + ExplodedNode<ValueState>* Node = WS.back(); + WS.pop_back(); + + if (Visited.find(Node) != Visited.end()) + continue; + + Visited[Node] = cnt++; + + if (Node->pred_empty()) { + Root = Node; + break; + } + + for (ExplodedNode<ValueState>::pred_iterator I=Node->pred_begin(), + E=Node->pred_end(); I!=E; ++I) + WS.push_back(*I); + } - while (N) { - Visited.insert(N); + assert (Root); + + // Now walk from the root down the DFS path, always taking the successor + // with the lowest number. + ExplodedNode<ValueState> *Last = 0, *First = 0; - ExplodedNode<ValueState>* NewN = - G->getNode(N->getLocation(), N->getState()); + for ( N = Root ;;) { - if (!First) First = NewN; - if (Last) Last->addPredecessor(NewN); + // Lookup the number associated with the current node. + llvm::DenseMap<void*,unsigned>::iterator I=Visited.find(N); + assert (I != Visited.end()); - Last = NewN; + // Create the equivalent node in the new graph with the same state + // and location. + ExplodedNode<ValueState>* NewN = + G->getNode(N->getLocation(), N->getState()); + + // Link up the new node with the previous node. + if (Last) + NewN->addPredecessor(Last); - if (N->pred_empty()) + Last = NewN; + + // Are we at the final node? + if (I->second == 0) { + First = NewN; break; - - ExplodedNode<ValueState>::pred_iterator PI = N->pred_begin(); - ExplodedNode<ValueState>::pred_iterator PE = N->pred_end(); + } + + // Find the next successor node. We choose the node that is marked + // with the lowest DFS number. + ExplodedNode<ValueState>::succ_iterator SI = N->succ_begin(); + ExplodedNode<ValueState>::succ_iterator SE = N->succ_end(); N = 0; - // Look for the first predecessor that we have not already visited. + for (unsigned MinVal = 0; SI != SE; ++SI) { - for (; PI != PE; ++PI) - if (!Visited.count(*PI)) { - N = *PI; - break; + I = Visited.find(*SI); + + if (I == Visited.end()) + continue; + + if (!N || I->second < MinVal) { + N = *SI; + MinVal = I->second; } - - assert (N && "All predecessors involved in a cycle!"); + } + + assert (N); } - + + assert (First); return std::make_pair(G, First); } diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp index 05f9303856..7c2ca0c13f 100644 --- a/lib/Analysis/GRCoreEngine.cpp +++ b/lib/Analysis/GRCoreEngine.cpp @@ -317,12 +317,30 @@ void GRStmtNodeBuilderImpl::GenerateAutoTransition(ExplodedNodeImpl* N) { Eng.WList->Enqueue(Succ, B, Idx+1); } +static inline ProgramPoint GetPostLoc(Stmt* S, ProgramPoint::Kind K) { + switch (K) { + default: + assert(false && "Invalid PostXXXKind."); + + case ProgramPoint::PostStmtKind: + return PostStmt(S); + + case ProgramPoint::PostLoadKind: + return PostLoad(S); + + case ProgramPoint::PostPurgeDeadSymbolsKind: + return PostPurgeDeadSymbols(S); + } +} + ExplodedNodeImpl* GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, void* State, - ExplodedNodeImpl* Pred, bool isLoad) { + ExplodedNodeImpl* Pred, + ProgramPoint::Kind K) { bool IsNew; - ProgramPoint Loc = isLoad ? PostLoad(S) : PostStmt(S); + ProgramPoint Loc = GetPostLoc(S, K); + ExplodedNodeImpl* N = Eng.G->getNodeImpl(Loc, State, &IsNew); N->addPredecessor(Pred); Deferred.erase(Pred); diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 837d910091..2580172d53 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -214,6 +214,9 @@ void GRExprEngine::ProcessStmt(Stmt* S, StmtNodeBuilder& builder) { SaveAndRestore<bool> OldSink(Builder->BuildSinks); SaveOr OldHasGen(Builder->HasGeneratedNode); + SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols); + Builder->PurgingDeadSymbols = true; + TF->EvalDeadSymbols(Tmp, *this, *Builder, EntryNode, S, CleanedState, DeadSymbols); @@ -965,7 +968,10 @@ ValueState* GRExprEngine::EvalLocation(Expr* Ex, NodeTy* Pred, // Check for loads/stores from/to undefined values. if (location.isUndef()) { - if (NodeTy* Succ = Builder->generateNode(Ex, St, Pred, isLoad)) { + ProgramPoint::Kind K = + isLoad ? ProgramPoint::PostLoadKind : ProgramPoint::PostStmtKind; + + if (NodeTy* Succ = Builder->generateNode(Ex, St, Pred, K)) { Succ->markAsSink(); UndefDeref.insert(Succ); } @@ -1000,7 +1006,10 @@ ValueState* GRExprEngine::EvalLocation(Expr* Ex, NodeTy* Pred, // We don't use "MakeNode" here because the node will be a sink // and we have no intention of processing it later. - NodeTy* NullNode = Builder->generateNode(Ex, StNull, Pred, isLoad); + ProgramPoint::Kind K = + isLoad ? ProgramPoint::PostLoadKind : ProgramPoint::PostStmtKind; + + NodeTy* NullNode = Builder->generateNode(Ex, StNull, Pred, K); if (NullNode) { @@ -2437,6 +2446,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<GRExprEngine::NodeTy*> : break; case ProgramPoint::PostLoadKind: + case ProgramPoint::PostPurgeDeadSymbolsKind: case ProgramPoint::PostStmtKind: { const PostStmt& L = cast<PostStmt>(Loc); Stmt* S = L.getStmt(); |