diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Analysis/BugReporter.cpp | 97 | ||||
-rw-r--r-- | lib/Analysis/GRCoreEngine.cpp | 22 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 14 |
3 files changed, 102 insertions, 31 deletions
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(); |