blob: 864a83b88479549a6c2a1a7c3e2ca2c1ab225285 [file] [log] [blame]
Ted Kremenek9eb49a42008-01-13 04:56:13 +00001//=-- 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 Kremenek33c63692008-04-16 15:51:26 +000016#include "clang/AST/Stmt.h"
Ted Kremenekffe0f432008-03-07 22:58:01 +000017#include "llvm/ADT/DenseSet.h"
18#include "llvm/ADT/DenseMap.h"
19#include "llvm/ADT/SmallVector.h"
Ted Kremenek9eb49a42008-01-13 04:56:13 +000020#include <vector>
Ted Kremenek7ec07fd2008-03-12 17:18:20 +000021#include <list>
Ted Kremenek9eb49a42008-01-13 04:56:13 +000022
23using namespace clang;
24
Ted Kremenek2e287542008-08-27 01:56:11 +000025//===----------------------------------------------------------------------===//
26// Node auditing.
27//===----------------------------------------------------------------------===//
28
29// An out of line virtual method to provide a home for the class vtable.
30ExplodedNodeImpl::Auditor::~Auditor() {}
31
32#ifndef NDEBUG
33static ExplodedNodeImpl::Auditor* NodeAuditor = 0;
34#endif
35
36void ExplodedNodeImpl::SetAuditor(ExplodedNodeImpl::Auditor* A) {
37#ifndef NDEBUG
38 NodeAuditor = A;
39#endif
40}
41
42//===----------------------------------------------------------------------===//
43// ExplodedNodeImpl.
44//===----------------------------------------------------------------------===//
Ted Kremenek9eb49a42008-01-13 04:56:13 +000045
46static inline std::vector<ExplodedNodeImpl*>& getVector(void* P) {
47 return *reinterpret_cast<std::vector<ExplodedNodeImpl*>*>(P);
48}
49
Ted Kremenek45b87892008-08-27 01:27:52 +000050void ExplodedNodeImpl::addPredecessor(ExplodedNodeImpl* V) {
51 assert (!V->isSink());
52 Preds.addNode(V);
53 V->Succs.addNode(this);
Ted Kremenek2e287542008-08-27 01:56:11 +000054#ifndef NDEBUG
55 if (NodeAuditor) NodeAuditor->AddEdge(V, this);
56#endif
Ted Kremenek45b87892008-08-27 01:27:52 +000057}
58
Ted Kremenek9eb49a42008-01-13 04:56:13 +000059void ExplodedNodeImpl::NodeGroup::addNode(ExplodedNodeImpl* N) {
Ted Kremenek596f0a12008-03-05 19:08:55 +000060
61 assert ((reinterpret_cast<uintptr_t>(N) & Mask) == 0x0);
Ted Kremenekffe0f432008-03-07 22:58:01 +000062 assert (!getFlag());
Ted Kremenek596f0a12008-03-05 19:08:55 +000063
Ted Kremenek9eb49a42008-01-13 04:56:13 +000064 if (getKind() == Size1) {
65 if (ExplodedNodeImpl* NOld = getNode()) {
66 std::vector<ExplodedNodeImpl*>* V = new std::vector<ExplodedNodeImpl*>();
Ted Kremenek596f0a12008-03-05 19:08:55 +000067 assert ((reinterpret_cast<uintptr_t>(V) & Mask) == 0x0);
Ted Kremenek9eb49a42008-01-13 04:56:13 +000068 V->push_back(NOld);
69 V->push_back(N);
Ted Kremenek45c63bd2008-01-29 23:31:09 +000070 P = reinterpret_cast<uintptr_t>(V) | SizeOther;
Ted Kremenek596f0a12008-03-05 19:08:55 +000071 assert (getPtr() == (void*) V);
72 assert (getKind() == SizeOther);
Ted Kremenek9eb49a42008-01-13 04:56:13 +000073 }
Ted Kremenek596f0a12008-03-05 19:08:55 +000074 else {
Ted Kremenek9eb49a42008-01-13 04:56:13 +000075 P = reinterpret_cast<uintptr_t>(N);
Ted Kremenek596f0a12008-03-05 19:08:55 +000076 assert (getKind() == Size1);
77 }
Ted Kremenek9eb49a42008-01-13 04:56:13 +000078 }
Ted Kremenek596f0a12008-03-05 19:08:55 +000079 else {
80 assert (getKind() == SizeOther);
Ted Kremenek9eb49a42008-01-13 04:56:13 +000081 getVector(getPtr()).push_back(N);
Ted Kremenek596f0a12008-03-05 19:08:55 +000082 }
Ted Kremenek9eb49a42008-01-13 04:56:13 +000083}
84
Ted Kremenek9eb49a42008-01-13 04:56:13 +000085
86unsigned ExplodedNodeImpl::NodeGroup::size() const {
Ted Kremenekffe0f432008-03-07 22:58:01 +000087 if (getFlag())
88 return 0;
89
Ted Kremenek9eb49a42008-01-13 04:56:13 +000090 if (getKind() == Size1)
91 return getNode() ? 1 : 0;
92 else
93 return getVector(getPtr()).size();
94}
95
96ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::begin() const {
Ted Kremenekffe0f432008-03-07 22:58:01 +000097 if (getFlag())
98 return NULL;
99
Ted Kremenek9eb49a42008-01-13 04:56:13 +0000100 if (getKind() == Size1)
Ted Kremenekffe0f432008-03-07 22:58:01 +0000101 return (ExplodedNodeImpl**) (getPtr() ? &P : NULL);
Ted Kremenek9eb49a42008-01-13 04:56:13 +0000102 else
103 return const_cast<ExplodedNodeImpl**>(&*(getVector(getPtr()).begin()));
104}
105
106ExplodedNodeImpl** ExplodedNodeImpl::NodeGroup::end() const {
Ted Kremenekffe0f432008-03-07 22:58:01 +0000107 if (getFlag())
108 return NULL;
109
Ted Kremenek9eb49a42008-01-13 04:56:13 +0000110 if (getKind() == Size1)
Ted Kremenekffe0f432008-03-07 22:58:01 +0000111 return (ExplodedNodeImpl**) (getPtr() ? &P+1 : NULL);
Ted Kremenek7b989572008-04-20 23:54:24 +0000112 else {
113 // Dereferencing end() is undefined behaviour. The vector is not empty, so
Argyrios Kyrtzidis5fc073f2008-04-22 07:37:18 +0000114 // we can dereference the last elem and then add 1 to the result.
115 return const_cast<ExplodedNodeImpl**>(&getVector(getPtr()).back()) + 1;
Ted Kremenek7b989572008-04-20 23:54:24 +0000116 }
Ted Kremenek9eb49a42008-01-13 04:56:13 +0000117}
118
119ExplodedNodeImpl::NodeGroup::~NodeGroup() {
120 if (getKind() == SizeOther) delete &getVector(getPtr());
121}
Ted Kremenekffe0f432008-03-07 22:58:01 +0000122
Ted Kremenek3148eb42009-01-24 00:55:43 +0000123ExplodedGraphImpl*
124ExplodedGraphImpl::Trim(const ExplodedNodeImpl* const* BeginSources,
Ted Kremenekcf118d42009-02-04 23:49:09 +0000125 const ExplodedNodeImpl* const* EndSources,
126 InterExplodedGraphMapImpl* M) const {
Ted Kremenekffe0f432008-03-07 22:58:01 +0000127
Ted Kremenekcf118d42009-02-04 23:49:09 +0000128 typedef llvm::DenseMap<const ExplodedNodeImpl*,
129 const ExplodedNodeImpl*> Pass1Ty;
Ted Kremenekffe0f432008-03-07 22:58:01 +0000130 Pass1Ty Pass1;
Ted Kremenekcf118d42009-02-04 23:49:09 +0000131
132 typedef llvm::DenseMap<const ExplodedNodeImpl*,
133 ExplodedNodeImpl*> Pass2Ty;
134
135 Pass2Ty& Pass2 = M->M;
Ted Kremenekffe0f432008-03-07 22:58:01 +0000136
Ted Kremenek3148eb42009-01-24 00:55:43 +0000137 llvm::SmallVector<const ExplodedNodeImpl*, 10> WL2;
Ted Kremenekffe0f432008-03-07 22:58:01 +0000138
139 { // ===- Pass 1 (reverse BFS) -===
140
141 // Enqueue the source nodes to the first worklist.
142
Ted Kremenek3148eb42009-01-24 00:55:43 +0000143 std::list<std::pair<const ExplodedNodeImpl*,
144 const ExplodedNodeImpl*> > WL1, WL1_Loops;
Ted Kremenekffe0f432008-03-07 22:58:01 +0000145
Ted Kremenekcf118d42009-02-04 23:49:09 +0000146 for (const ExplodedNodeImpl* const* I = BeginSources; I != EndSources; ++I){
147 assert(*I);
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000148 WL1.push_back(std::make_pair(*I, *I));
Ted Kremenekcf118d42009-02-04 23:49:09 +0000149 }
Ted Kremenekffe0f432008-03-07 22:58:01 +0000150
151 // Process the worklist.
152
Ted Kremenekcf118d42009-02-04 23:49:09 +0000153 while (!WL1.empty() || !WL1_Loops.empty()) {
Ted Kremenek33c63692008-04-16 15:51:26 +0000154 // Only dequeue from the "loops" worklist if WL1 has no items.
155 // Thus we prioritize for paths that don't span loop boundaries.
Ted Kremenekcf118d42009-02-04 23:49:09 +0000156 const ExplodedNodeImpl *N = 0, *Src = 0;
Ted Kremenek3148eb42009-01-24 00:55:43 +0000157
Ted Kremenek33c63692008-04-16 15:51:26 +0000158 if (WL1.empty()) {
Ted Kremenekcf118d42009-02-04 23:49:09 +0000159 assert(!WL1_Loops.empty());
Ted Kremenek33c63692008-04-16 15:51:26 +0000160 N = WL1_Loops.back().first;
Ted Kremenekcf118d42009-02-04 23:49:09 +0000161 assert(N);
Ted Kremenek33c63692008-04-16 15:51:26 +0000162 Src = WL1_Loops.back().second;
163 WL1_Loops.pop_back();
164 }
165 else {
166 N = WL1.back().first;
Ted Kremenekcf118d42009-02-04 23:49:09 +0000167 assert(N);
Ted Kremenek33c63692008-04-16 15:51:26 +0000168 Src = WL1.back().second;
169 WL1.pop_back();
170 }
Ted Kremenekffe0f432008-03-07 22:58:01 +0000171
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000172 if (Pass1.find(N) != Pass1.end())
Ted Kremenekffe0f432008-03-07 22:58:01 +0000173 continue;
174
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000175 bool PredHasSameSource = false;
176 bool VisitPreds = true;
177
178 for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end();
179 I!=E; ++I) {
180
181 Pass1Ty::iterator pi = Pass1.find(*I);
182
183 if (pi == Pass1.end())
184 continue;
185
186 VisitPreds = false;
187
188 if (pi->second == Src) {
189 PredHasSameSource = true;
190 break;
191 }
Ted Kremenekffe0f432008-03-07 22:58:01 +0000192 }
193
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000194 if (VisitPreds || !PredHasSameSource) {
195
196 Pass1[N] = Src;
197
198 if (N->Preds.empty()) {
199 WL2.push_back(N);
200 continue;
201 }
202 }
203 else
204 Pass1[N] = NULL;
205
206 if (VisitPreds)
207 for (ExplodedNodeImpl** I=N->Preds.begin(), **E=N->Preds.end();
Ted Kremenek33c63692008-04-16 15:51:26 +0000208 I!=E; ++I) {
209
210 ProgramPoint P = Src->getLocation();
211
212 if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P))
213 if (Stmt* T = BE->getSrc()->getTerminator())
214 switch (T->getStmtClass()) {
215 default: break;
216 case Stmt::ForStmtClass:
217 case Stmt::WhileStmtClass:
218 case Stmt::DoStmtClass:
Ted Kremenekcf118d42009-02-04 23:49:09 +0000219 assert(*I);
Ted Kremenek33c63692008-04-16 15:51:26 +0000220 WL1_Loops.push_front(std::make_pair(*I, Src));
221 continue;
222
223 }
224
Ted Kremenekcf118d42009-02-04 23:49:09 +0000225 assert(*I);
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000226 WL1.push_front(std::make_pair(*I, Src));
Ted Kremenek33c63692008-04-16 15:51:26 +0000227 }
Ted Kremenekffe0f432008-03-07 22:58:01 +0000228 }
229 }
230
231 if (WL2.empty())
Ted Kremenekcf118d42009-02-04 23:49:09 +0000232 return 0;
233
Ted Kremenekffe0f432008-03-07 22:58:01 +0000234 ExplodedGraphImpl* G = MakeEmptyGraph();
235
236 // ===- Pass 2 (forward DFS to construct the new graph) -===
237
238 while (!WL2.empty()) {
239
Ted Kremenek3148eb42009-01-24 00:55:43 +0000240 const ExplodedNodeImpl* N = WL2.back();
Ted Kremenekffe0f432008-03-07 22:58:01 +0000241 WL2.pop_back();
242
243 // Skip this node if we have already processed it.
244
245 if (Pass2.find(N) != Pass2.end())
246 continue;
247
248 // Create the corresponding node in the new graph.
249
250 ExplodedNodeImpl* NewN = G->getNodeImpl(N->getLocation(), N->State, NULL);
251 Pass2[N] = NewN;
252
253 if (N->Preds.empty())
254 G->addRoot(NewN);
255
256 // In the case that some of the intended predecessors of NewN have already
257 // been created, we should hook them up as predecessors.
258
259 for (ExplodedNodeImpl **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) {
260
261 Pass2Ty::iterator PI = Pass2.find(*I);
262
263 if (PI == Pass2.end())
264 continue;
265
266 NewN->addPredecessor(PI->second);
267 }
268
269 // In the case that some of the intended successors of NewN have already
270 // been created, we should hook them up as successors. Otherwise, enqueue
271 // the new nodes from the original graph that should have nodes created
272 // in the new graph.
273
274 for (ExplodedNodeImpl **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) {
275
276 Pass2Ty::iterator PI = Pass2.find(*I);
277
278 if (PI != Pass2.end()) {
279 PI->second->addPredecessor(NewN);
280 continue;
281 }
282
283 // Enqueue nodes to the worklist that were marked during pass 1.
284
Ted Kremenek7ec07fd2008-03-12 17:18:20 +0000285 Pass1Ty::iterator pi = Pass1.find(*I);
286
287 if (pi == Pass1.end() || pi->second == NULL)
288 continue;
289
290 WL2.push_back(*I);
Ted Kremenekffe0f432008-03-07 22:58:01 +0000291 }
292
293 if (N->isSink())
294 NewN->markAsSink();
295 }
296
297 return G;
298}
Ted Kremenekcf118d42009-02-04 23:49:09 +0000299
300ExplodedNodeImpl*
301InterExplodedGraphMapImpl::getMappedImplNode(const ExplodedNodeImpl* N) const {
302 llvm::DenseMap<const ExplodedNodeImpl*, ExplodedNodeImpl*>::iterator I =
303 M.find(N);
304
305 return I == M.end() ? 0 : I->second;
306}
307
308InterExplodedGraphMapImpl::InterExplodedGraphMapImpl() {}
309