| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 1 | //=-- ExplodedGraph.cpp - Local, Path-Sens. "Exploded Graph" -*- C++ -*------=// | 
 | 2 | // | 
 | 3 | //                     The LLVM Compiler Infrastructure | 
 | 4 | // | 
 | 5 | // This file is distributed under the University of Illinois Open Source | 
 | 6 | // License. See LICENSE.TXT for details. | 
 | 7 | // | 
 | 8 | //===----------------------------------------------------------------------===// | 
 | 9 | // | 
 | 10 | //  This file defines the template classes ExplodedNode and ExplodedGraph, | 
 | 11 | //  which represent a path-sensitive, intra-procedural "exploded graph." | 
 | 12 | // | 
 | 13 | //===----------------------------------------------------------------------===// | 
 | 14 |  | 
 | 15 | #include "clang/Analysis/PathSensitive/ExplodedGraph.h" | 
| Ted Kremenek | 33c6369 | 2008-04-16 15:51:26 +0000 | [diff] [blame] | 16 | #include "clang/AST/Stmt.h" | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 17 | #include "llvm/ADT/DenseSet.h" | 
 | 18 | #include "llvm/ADT/DenseMap.h" | 
 | 19 | #include "llvm/ADT/SmallVector.h" | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 20 | #include <vector> | 
| Ted Kremenek | 7ec07fd | 2008-03-12 17:18:20 +0000 | [diff] [blame] | 21 | #include <list> | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 22 |  | 
 | 23 | using namespace clang; | 
 | 24 |  | 
 | 25 |  | 
 | 26 | static inline std::vector<ExplodedNodeImpl*>& getVector(void* P) { | 
 | 27 |   return *reinterpret_cast<std::vector<ExplodedNodeImpl*>*>(P); | 
 | 28 | } | 
 | 29 |  | 
 | 30 | void ExplodedNodeImpl::NodeGroup::addNode(ExplodedNodeImpl* N) { | 
| Ted Kremenek | 596f0a1 | 2008-03-05 19:08:55 +0000 | [diff] [blame] | 31 |    | 
 | 32 |   assert ((reinterpret_cast<uintptr_t>(N) & Mask) == 0x0); | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 33 |   assert (!getFlag()); | 
| Ted Kremenek | 596f0a1 | 2008-03-05 19:08:55 +0000 | [diff] [blame] | 34 |    | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 35 |   if (getKind() == Size1) { | 
 | 36 |     if (ExplodedNodeImpl* NOld = getNode()) { | 
 | 37 |       std::vector<ExplodedNodeImpl*>* V = new std::vector<ExplodedNodeImpl*>(); | 
| Ted Kremenek | 596f0a1 | 2008-03-05 19:08:55 +0000 | [diff] [blame] | 38 |       assert ((reinterpret_cast<uintptr_t>(V) & Mask) == 0x0); | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 39 |       V->push_back(NOld); | 
 | 40 |       V->push_back(N); | 
| Ted Kremenek | 45c63bd | 2008-01-29 23:31:09 +0000 | [diff] [blame] | 41 |       P = reinterpret_cast<uintptr_t>(V) | SizeOther; | 
| Ted Kremenek | 596f0a1 | 2008-03-05 19:08:55 +0000 | [diff] [blame] | 42 |       assert (getPtr() == (void*) V); | 
 | 43 |       assert (getKind() == SizeOther); | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 44 |     } | 
| Ted Kremenek | 596f0a1 | 2008-03-05 19:08:55 +0000 | [diff] [blame] | 45 |     else { | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 46 |       P = reinterpret_cast<uintptr_t>(N); | 
| Ted Kremenek | 596f0a1 | 2008-03-05 19:08:55 +0000 | [diff] [blame] | 47 |       assert (getKind() == Size1); | 
 | 48 |     } | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 49 |   } | 
| Ted Kremenek | 596f0a1 | 2008-03-05 19:08:55 +0000 | [diff] [blame] | 50 |   else { | 
 | 51 |     assert (getKind() == SizeOther); | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 52 |     getVector(getPtr()).push_back(N); | 
| Ted Kremenek | 596f0a1 | 2008-03-05 19:08:55 +0000 | [diff] [blame] | 53 |   } | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 54 | } | 
 | 55 |  | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 56 |  | 
 | 57 | unsigned ExplodedNodeImpl::NodeGroup::size() const { | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 58 |   if (getFlag()) | 
 | 59 |     return 0; | 
 | 60 |    | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 61 |   if (getKind() == Size1) | 
 | 62 |     return getNode() ? 1 : 0; | 
 | 63 |   else | 
 | 64 |     return getVector(getPtr()).size(); | 
 | 65 | } | 
 | 66 |  | 
 | 67 | ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::begin() const { | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 68 |   if (getFlag()) | 
 | 69 |     return NULL; | 
 | 70 |    | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 71 |   if (getKind() == Size1) | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 72 |     return (ExplodedNodeImpl**) (getPtr() ? &P : NULL); | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 73 |   else | 
 | 74 |     return const_cast<ExplodedNodeImpl**>(&*(getVector(getPtr()).begin())); | 
 | 75 | } | 
 | 76 |  | 
 | 77 | ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::end() const { | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 78 |   if (getFlag()) | 
 | 79 |     return NULL; | 
 | 80 |    | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 81 |   if (getKind() == Size1) | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 82 |     return (ExplodedNodeImpl**) (getPtr() ? &P+1 : NULL); | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 83 |   else | 
| Ted Kremenek | 596f0a1 | 2008-03-05 19:08:55 +0000 | [diff] [blame] | 84 |     return const_cast<ExplodedNodeImpl**>(&*(getVector(getPtr()).end())); | 
| Ted Kremenek | 9eb49a4 | 2008-01-13 04:56:13 +0000 | [diff] [blame] | 85 | } | 
 | 86 |  | 
 | 87 | ExplodedNodeImpl::NodeGroup::~NodeGroup() { | 
 | 88 |   if (getKind() == SizeOther) delete &getVector(getPtr()); | 
 | 89 | } | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 90 |  | 
 | 91 | ExplodedGraphImpl* ExplodedGraphImpl::Trim(ExplodedNodeImpl** BeginSources, | 
 | 92 |                                            ExplodedNodeImpl** EndSources) const{ | 
 | 93 |    | 
| Ted Kremenek | 7ec07fd | 2008-03-12 17:18:20 +0000 | [diff] [blame] | 94 |   typedef llvm::DenseMap<ExplodedNodeImpl*, ExplodedNodeImpl*> Pass1Ty; | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 95 |   typedef llvm::DenseMap<ExplodedNodeImpl*, ExplodedNodeImpl*> Pass2Ty; | 
 | 96 |    | 
 | 97 |   Pass1Ty Pass1; | 
 | 98 |   Pass2Ty Pass2; | 
 | 99 |    | 
 | 100 |   llvm::SmallVector<ExplodedNodeImpl*, 10> WL2; | 
 | 101 |  | 
 | 102 |   { // ===- Pass 1 (reverse BFS) -=== | 
 | 103 |      | 
 | 104 |     // Enqueue the source nodes to the first worklist.  | 
 | 105 |      | 
| Ted Kremenek | 7ec07fd | 2008-03-12 17:18:20 +0000 | [diff] [blame] | 106 |     std::list<std::pair<ExplodedNodeImpl*, ExplodedNodeImpl*> > WL1; | 
| Ted Kremenek | 33c6369 | 2008-04-16 15:51:26 +0000 | [diff] [blame] | 107 |     std::list<std::pair<ExplodedNodeImpl*, ExplodedNodeImpl*> > WL1_Loops; | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 108 |    | 
 | 109 |     for (ExplodedNodeImpl** I = BeginSources; I != EndSources; ++I) | 
| Ted Kremenek | 7ec07fd | 2008-03-12 17:18:20 +0000 | [diff] [blame] | 110 |       WL1.push_back(std::make_pair(*I, *I)); | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 111 |      | 
 | 112 |     // Process the worklist. | 
 | 113 |  | 
| Ted Kremenek | 33c6369 | 2008-04-16 15:51:26 +0000 | [diff] [blame] | 114 |     while (! (WL1.empty() && WL1_Loops.empty())) { | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 115 |        | 
| Ted Kremenek | 33c6369 | 2008-04-16 15:51:26 +0000 | [diff] [blame] | 116 |       ExplodedNodeImpl *N, *Src; | 
 | 117 |  | 
 | 118 |       // Only dequeue from the "loops" worklist if WL1 has no items. | 
 | 119 |       // Thus we prioritize for paths that don't span loop boundaries. | 
| Ted Kremenek | 7ec07fd | 2008-03-12 17:18:20 +0000 | [diff] [blame] | 120 |        | 
| Ted Kremenek | 33c6369 | 2008-04-16 15:51:26 +0000 | [diff] [blame] | 121 |       if (WL1.empty()) { | 
 | 122 |         N = WL1_Loops.back().first; | 
 | 123 |         Src = WL1_Loops.back().second; | 
 | 124 |         WL1_Loops.pop_back(); | 
 | 125 |       } | 
 | 126 |       else { | 
 | 127 |         N = WL1.back().first; | 
 | 128 |         Src = WL1.back().second; | 
 | 129 |         WL1.pop_back(); | 
 | 130 |       }       | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 131 |        | 
| Ted Kremenek | 7ec07fd | 2008-03-12 17:18:20 +0000 | [diff] [blame] | 132 |       if (Pass1.find(N) != Pass1.end()) | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 133 |         continue; | 
 | 134 |        | 
| Ted Kremenek | 7ec07fd | 2008-03-12 17:18:20 +0000 | [diff] [blame] | 135 |       bool PredHasSameSource = false; | 
 | 136 |       bool VisitPreds = true; | 
 | 137 |              | 
 | 138 |       for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end(); | 
 | 139 |             I!=E; ++I) { | 
 | 140 |          | 
 | 141 |         Pass1Ty::iterator pi = Pass1.find(*I); | 
 | 142 |          | 
 | 143 |         if (pi == Pass1.end()) | 
 | 144 |           continue; | 
 | 145 |          | 
 | 146 |         VisitPreds = false; | 
 | 147 |          | 
 | 148 |         if (pi->second == Src) { | 
 | 149 |           PredHasSameSource = true; | 
 | 150 |           break; | 
 | 151 |         } | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 152 |       } | 
 | 153 |        | 
| Ted Kremenek | 7ec07fd | 2008-03-12 17:18:20 +0000 | [diff] [blame] | 154 |       if (VisitPreds || !PredHasSameSource) { | 
 | 155 |          | 
 | 156 |         Pass1[N] = Src; | 
 | 157 |        | 
 | 158 |         if (N->Preds.empty()) { | 
 | 159 |           WL2.push_back(N); | 
 | 160 |           continue;       | 
 | 161 |         } | 
 | 162 |       } | 
 | 163 |       else | 
 | 164 |         Pass1[N] = NULL; | 
 | 165 |        | 
 | 166 |       if (VisitPreds) | 
 | 167 |         for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end(); | 
| Ted Kremenek | 33c6369 | 2008-04-16 15:51:26 +0000 | [diff] [blame] | 168 |              I!=E; ++I) { | 
 | 169 |            | 
 | 170 |           ProgramPoint P = Src->getLocation(); | 
 | 171 |            | 
 | 172 |           if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) | 
 | 173 |             if (Stmt* T = BE->getSrc()->getTerminator()) | 
 | 174 |               switch (T->getStmtClass()) { | 
 | 175 |                 default: break; | 
 | 176 |                 case Stmt::ForStmtClass: | 
 | 177 |                 case Stmt::WhileStmtClass: | 
 | 178 |                 case Stmt::DoStmtClass: | 
 | 179 |                   WL1_Loops.push_front(std::make_pair(*I, Src)); | 
 | 180 |                   continue; | 
 | 181 |                    | 
 | 182 |               } | 
 | 183 |            | 
| Ted Kremenek | 7ec07fd | 2008-03-12 17:18:20 +0000 | [diff] [blame] | 184 |           WL1.push_front(std::make_pair(*I, Src)); | 
| Ted Kremenek | 33c6369 | 2008-04-16 15:51:26 +0000 | [diff] [blame] | 185 |         } | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 186 |     } | 
 | 187 |   } | 
 | 188 |    | 
 | 189 |   if (WL2.empty()) | 
 | 190 |     return NULL; | 
 | 191 |      | 
 | 192 |   ExplodedGraphImpl* G = MakeEmptyGraph(); | 
 | 193 |    | 
 | 194 |   // ===- Pass 2 (forward DFS to construct the new graph) -=== | 
 | 195 |    | 
 | 196 |   while (!WL2.empty()) { | 
 | 197 |      | 
 | 198 |     ExplodedNodeImpl* N = WL2.back(); | 
 | 199 |     WL2.pop_back(); | 
 | 200 |      | 
 | 201 |     // Skip this node if we have already processed it. | 
 | 202 |      | 
 | 203 |     if (Pass2.find(N) != Pass2.end()) | 
 | 204 |       continue; | 
 | 205 |      | 
 | 206 |     // Create the corresponding node in the new graph. | 
 | 207 |      | 
 | 208 |     ExplodedNodeImpl* NewN = G->getNodeImpl(N->getLocation(), N->State, NULL); | 
 | 209 |     Pass2[N] = NewN; | 
 | 210 |      | 
 | 211 |     if (N->Preds.empty()) | 
 | 212 |       G->addRoot(NewN); | 
 | 213 |      | 
 | 214 |     // In the case that some of the intended predecessors of NewN have already | 
 | 215 |     // been created, we should hook them up as predecessors. | 
 | 216 |      | 
 | 217 |     for (ExplodedNodeImpl **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) { | 
 | 218 |          | 
 | 219 |       Pass2Ty::iterator PI = Pass2.find(*I); | 
 | 220 |  | 
 | 221 |       if (PI == Pass2.end()) | 
 | 222 |         continue; | 
 | 223 |        | 
 | 224 |       NewN->addPredecessor(PI->second); | 
 | 225 |     } | 
 | 226 |  | 
 | 227 |     // In the case that some of the intended successors of NewN have already | 
 | 228 |     // been created, we should hook them up as successors.  Otherwise, enqueue | 
 | 229 |     // the new nodes from the original graph that should have nodes created | 
 | 230 |     // in the new graph. | 
 | 231 |     | 
 | 232 |     for (ExplodedNodeImpl **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) { | 
 | 233 |        | 
 | 234 |       Pass2Ty::iterator PI = Pass2.find(*I); | 
 | 235 |        | 
 | 236 |       if (PI != Pass2.end()) { | 
 | 237 |         PI->second->addPredecessor(NewN); | 
 | 238 |         continue; | 
 | 239 |       } | 
 | 240 |  | 
 | 241 |       // Enqueue nodes to the worklist that were marked during pass 1. | 
 | 242 |        | 
| Ted Kremenek | 7ec07fd | 2008-03-12 17:18:20 +0000 | [diff] [blame] | 243 |       Pass1Ty::iterator pi = Pass1.find(*I); | 
 | 244 |        | 
 | 245 |       if (pi == Pass1.end() || pi->second == NULL) | 
 | 246 |         continue; | 
 | 247 |              | 
 | 248 |       WL2.push_back(*I); | 
| Ted Kremenek | ffe0f43 | 2008-03-07 22:58:01 +0000 | [diff] [blame] | 249 |     } | 
 | 250 |      | 
 | 251 |     if (N->isSink()) | 
 | 252 |       NewN->markAsSink(); | 
 | 253 |   } | 
 | 254 |      | 
 | 255 |   return G; | 
 | 256 | } |