1*fa0734ecSArgyrios Kyrtzidis //=-- ExplodedGraph.cpp - Local, Path-Sens. "Exploded Graph" -*- C++ -*------=//
2*fa0734ecSArgyrios Kyrtzidis //
3*fa0734ecSArgyrios Kyrtzidis //                     The LLVM Compiler Infrastructure
4*fa0734ecSArgyrios Kyrtzidis //
5*fa0734ecSArgyrios Kyrtzidis // This file is distributed under the University of Illinois Open Source
6*fa0734ecSArgyrios Kyrtzidis // License. See LICENSE.TXT for details.
7*fa0734ecSArgyrios Kyrtzidis //
8*fa0734ecSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
9*fa0734ecSArgyrios Kyrtzidis //
10*fa0734ecSArgyrios Kyrtzidis //  This file defines the template classes ExplodedNode and ExplodedGraph,
11*fa0734ecSArgyrios Kyrtzidis //  which represent a path-sensitive, intra-procedural "exploded graph."
12*fa0734ecSArgyrios Kyrtzidis //
13*fa0734ecSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
14*fa0734ecSArgyrios Kyrtzidis 
15*fa0734ecSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
16*fa0734ecSArgyrios Kyrtzidis #include "clang/StaticAnalyzer/PathSensitive/GRState.h"
17*fa0734ecSArgyrios Kyrtzidis #include "clang/AST/Stmt.h"
18*fa0734ecSArgyrios Kyrtzidis #include "llvm/ADT/DenseSet.h"
19*fa0734ecSArgyrios Kyrtzidis #include "llvm/ADT/DenseMap.h"
20*fa0734ecSArgyrios Kyrtzidis #include "llvm/ADT/SmallVector.h"
21*fa0734ecSArgyrios Kyrtzidis #include <vector>
22*fa0734ecSArgyrios Kyrtzidis 
23*fa0734ecSArgyrios Kyrtzidis using namespace clang;
24*fa0734ecSArgyrios Kyrtzidis using namespace ento;
25*fa0734ecSArgyrios Kyrtzidis 
26*fa0734ecSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
27*fa0734ecSArgyrios Kyrtzidis // Node auditing.
28*fa0734ecSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
29*fa0734ecSArgyrios Kyrtzidis 
30*fa0734ecSArgyrios Kyrtzidis // An out of line virtual method to provide a home for the class vtable.
31*fa0734ecSArgyrios Kyrtzidis ExplodedNode::Auditor::~Auditor() {}
32*fa0734ecSArgyrios Kyrtzidis 
33*fa0734ecSArgyrios Kyrtzidis #ifndef NDEBUG
34*fa0734ecSArgyrios Kyrtzidis static ExplodedNode::Auditor* NodeAuditor = 0;
35*fa0734ecSArgyrios Kyrtzidis #endif
36*fa0734ecSArgyrios Kyrtzidis 
37*fa0734ecSArgyrios Kyrtzidis void ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) {
38*fa0734ecSArgyrios Kyrtzidis #ifndef NDEBUG
39*fa0734ecSArgyrios Kyrtzidis   NodeAuditor = A;
40*fa0734ecSArgyrios Kyrtzidis #endif
41*fa0734ecSArgyrios Kyrtzidis }
42*fa0734ecSArgyrios Kyrtzidis 
43*fa0734ecSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
44*fa0734ecSArgyrios Kyrtzidis // ExplodedNode.
45*fa0734ecSArgyrios Kyrtzidis //===----------------------------------------------------------------------===//
46*fa0734ecSArgyrios Kyrtzidis 
47*fa0734ecSArgyrios Kyrtzidis static inline BumpVector<ExplodedNode*>& getVector(void* P) {
48*fa0734ecSArgyrios Kyrtzidis   return *reinterpret_cast<BumpVector<ExplodedNode*>*>(P);
49*fa0734ecSArgyrios Kyrtzidis }
50*fa0734ecSArgyrios Kyrtzidis 
51*fa0734ecSArgyrios Kyrtzidis void ExplodedNode::addPredecessor(ExplodedNode* V, ExplodedGraph &G) {
52*fa0734ecSArgyrios Kyrtzidis   assert (!V->isSink());
53*fa0734ecSArgyrios Kyrtzidis   Preds.addNode(V, G);
54*fa0734ecSArgyrios Kyrtzidis   V->Succs.addNode(this, G);
55*fa0734ecSArgyrios Kyrtzidis #ifndef NDEBUG
56*fa0734ecSArgyrios Kyrtzidis   if (NodeAuditor) NodeAuditor->AddEdge(V, this);
57*fa0734ecSArgyrios Kyrtzidis #endif
58*fa0734ecSArgyrios Kyrtzidis }
59*fa0734ecSArgyrios Kyrtzidis 
60*fa0734ecSArgyrios Kyrtzidis void ExplodedNode::NodeGroup::addNode(ExplodedNode* N, ExplodedGraph &G) {
61*fa0734ecSArgyrios Kyrtzidis   assert((reinterpret_cast<uintptr_t>(N) & Mask) == 0x0);
62*fa0734ecSArgyrios Kyrtzidis   assert(!getFlag());
63*fa0734ecSArgyrios Kyrtzidis 
64*fa0734ecSArgyrios Kyrtzidis   if (getKind() == Size1) {
65*fa0734ecSArgyrios Kyrtzidis     if (ExplodedNode* NOld = getNode()) {
66*fa0734ecSArgyrios Kyrtzidis       BumpVectorContext &Ctx = G.getNodeAllocator();
67*fa0734ecSArgyrios Kyrtzidis       BumpVector<ExplodedNode*> *V =
68*fa0734ecSArgyrios Kyrtzidis         G.getAllocator().Allocate<BumpVector<ExplodedNode*> >();
69*fa0734ecSArgyrios Kyrtzidis       new (V) BumpVector<ExplodedNode*>(Ctx, 4);
70*fa0734ecSArgyrios Kyrtzidis 
71*fa0734ecSArgyrios Kyrtzidis       assert((reinterpret_cast<uintptr_t>(V) & Mask) == 0x0);
72*fa0734ecSArgyrios Kyrtzidis       V->push_back(NOld, Ctx);
73*fa0734ecSArgyrios Kyrtzidis       V->push_back(N, Ctx);
74*fa0734ecSArgyrios Kyrtzidis       P = reinterpret_cast<uintptr_t>(V) | SizeOther;
75*fa0734ecSArgyrios Kyrtzidis       assert(getPtr() == (void*) V);
76*fa0734ecSArgyrios Kyrtzidis       assert(getKind() == SizeOther);
77*fa0734ecSArgyrios Kyrtzidis     }
78*fa0734ecSArgyrios Kyrtzidis     else {
79*fa0734ecSArgyrios Kyrtzidis       P = reinterpret_cast<uintptr_t>(N);
80*fa0734ecSArgyrios Kyrtzidis       assert(getKind() == Size1);
81*fa0734ecSArgyrios Kyrtzidis     }
82*fa0734ecSArgyrios Kyrtzidis   }
83*fa0734ecSArgyrios Kyrtzidis   else {
84*fa0734ecSArgyrios Kyrtzidis     assert(getKind() == SizeOther);
85*fa0734ecSArgyrios Kyrtzidis     getVector(getPtr()).push_back(N, G.getNodeAllocator());
86*fa0734ecSArgyrios Kyrtzidis   }
87*fa0734ecSArgyrios Kyrtzidis }
88*fa0734ecSArgyrios Kyrtzidis 
89*fa0734ecSArgyrios Kyrtzidis unsigned ExplodedNode::NodeGroup::size() const {
90*fa0734ecSArgyrios Kyrtzidis   if (getFlag())
91*fa0734ecSArgyrios Kyrtzidis     return 0;
92*fa0734ecSArgyrios Kyrtzidis 
93*fa0734ecSArgyrios Kyrtzidis   if (getKind() == Size1)
94*fa0734ecSArgyrios Kyrtzidis     return getNode() ? 1 : 0;
95*fa0734ecSArgyrios Kyrtzidis   else
96*fa0734ecSArgyrios Kyrtzidis     return getVector(getPtr()).size();
97*fa0734ecSArgyrios Kyrtzidis }
98*fa0734ecSArgyrios Kyrtzidis 
99*fa0734ecSArgyrios Kyrtzidis ExplodedNode **ExplodedNode::NodeGroup::begin() const {
100*fa0734ecSArgyrios Kyrtzidis   if (getFlag())
101*fa0734ecSArgyrios Kyrtzidis     return NULL;
102*fa0734ecSArgyrios Kyrtzidis 
103*fa0734ecSArgyrios Kyrtzidis   if (getKind() == Size1)
104*fa0734ecSArgyrios Kyrtzidis     return (ExplodedNode**) (getPtr() ? &P : NULL);
105*fa0734ecSArgyrios Kyrtzidis   else
106*fa0734ecSArgyrios Kyrtzidis     return const_cast<ExplodedNode**>(&*(getVector(getPtr()).begin()));
107*fa0734ecSArgyrios Kyrtzidis }
108*fa0734ecSArgyrios Kyrtzidis 
109*fa0734ecSArgyrios Kyrtzidis ExplodedNode** ExplodedNode::NodeGroup::end() const {
110*fa0734ecSArgyrios Kyrtzidis   if (getFlag())
111*fa0734ecSArgyrios Kyrtzidis     return NULL;
112*fa0734ecSArgyrios Kyrtzidis 
113*fa0734ecSArgyrios Kyrtzidis   if (getKind() == Size1)
114*fa0734ecSArgyrios Kyrtzidis     return (ExplodedNode**) (getPtr() ? &P+1 : NULL);
115*fa0734ecSArgyrios Kyrtzidis   else {
116*fa0734ecSArgyrios Kyrtzidis     // Dereferencing end() is undefined behaviour. The vector is not empty, so
117*fa0734ecSArgyrios Kyrtzidis     // we can dereference the last elem and then add 1 to the result.
118*fa0734ecSArgyrios Kyrtzidis     return const_cast<ExplodedNode**>(getVector(getPtr()).end());
119*fa0734ecSArgyrios Kyrtzidis   }
120*fa0734ecSArgyrios Kyrtzidis }
121*fa0734ecSArgyrios Kyrtzidis 
122*fa0734ecSArgyrios Kyrtzidis ExplodedNode *ExplodedGraph::getNode(const ProgramPoint& L,
123*fa0734ecSArgyrios Kyrtzidis                                      const GRState* State, bool* IsNew) {
124*fa0734ecSArgyrios Kyrtzidis   // Profile 'State' to determine if we already have an existing node.
125*fa0734ecSArgyrios Kyrtzidis   llvm::FoldingSetNodeID profile;
126*fa0734ecSArgyrios Kyrtzidis   void* InsertPos = 0;
127*fa0734ecSArgyrios Kyrtzidis 
128*fa0734ecSArgyrios Kyrtzidis   NodeTy::Profile(profile, L, State);
129*fa0734ecSArgyrios Kyrtzidis   NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos);
130*fa0734ecSArgyrios Kyrtzidis 
131*fa0734ecSArgyrios Kyrtzidis   if (!V) {
132*fa0734ecSArgyrios Kyrtzidis     // Allocate a new node.
133*fa0734ecSArgyrios Kyrtzidis     V = (NodeTy*) getAllocator().Allocate<NodeTy>();
134*fa0734ecSArgyrios Kyrtzidis     new (V) NodeTy(L, State);
135*fa0734ecSArgyrios Kyrtzidis 
136*fa0734ecSArgyrios Kyrtzidis     // Insert the node into the node set and return it.
137*fa0734ecSArgyrios Kyrtzidis     Nodes.InsertNode(V, InsertPos);
138*fa0734ecSArgyrios Kyrtzidis 
139*fa0734ecSArgyrios Kyrtzidis     ++NumNodes;
140*fa0734ecSArgyrios Kyrtzidis 
141*fa0734ecSArgyrios Kyrtzidis     if (IsNew) *IsNew = true;
142*fa0734ecSArgyrios Kyrtzidis   }
143*fa0734ecSArgyrios Kyrtzidis   else
144*fa0734ecSArgyrios Kyrtzidis     if (IsNew) *IsNew = false;
145*fa0734ecSArgyrios Kyrtzidis 
146*fa0734ecSArgyrios Kyrtzidis   return V;
147*fa0734ecSArgyrios Kyrtzidis }
148*fa0734ecSArgyrios Kyrtzidis 
149*fa0734ecSArgyrios Kyrtzidis std::pair<ExplodedGraph*, InterExplodedGraphMap*>
150*fa0734ecSArgyrios Kyrtzidis ExplodedGraph::Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
151*fa0734ecSArgyrios Kyrtzidis                llvm::DenseMap<const void*, const void*> *InverseMap) const {
152*fa0734ecSArgyrios Kyrtzidis 
153*fa0734ecSArgyrios Kyrtzidis   if (NBeg == NEnd)
154*fa0734ecSArgyrios Kyrtzidis     return std::make_pair((ExplodedGraph*) 0,
155*fa0734ecSArgyrios Kyrtzidis                           (InterExplodedGraphMap*) 0);
156*fa0734ecSArgyrios Kyrtzidis 
157*fa0734ecSArgyrios Kyrtzidis   assert (NBeg < NEnd);
158*fa0734ecSArgyrios Kyrtzidis 
159*fa0734ecSArgyrios Kyrtzidis   llvm::OwningPtr<InterExplodedGraphMap> M(new InterExplodedGraphMap());
160*fa0734ecSArgyrios Kyrtzidis 
161*fa0734ecSArgyrios Kyrtzidis   ExplodedGraph* G = TrimInternal(NBeg, NEnd, M.get(), InverseMap);
162*fa0734ecSArgyrios Kyrtzidis 
163*fa0734ecSArgyrios Kyrtzidis   return std::make_pair(static_cast<ExplodedGraph*>(G), M.take());
164*fa0734ecSArgyrios Kyrtzidis }
165*fa0734ecSArgyrios Kyrtzidis 
166*fa0734ecSArgyrios Kyrtzidis ExplodedGraph*
167*fa0734ecSArgyrios Kyrtzidis ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
168*fa0734ecSArgyrios Kyrtzidis                             const ExplodedNode* const* EndSources,
169*fa0734ecSArgyrios Kyrtzidis                             InterExplodedGraphMap* M,
170*fa0734ecSArgyrios Kyrtzidis                    llvm::DenseMap<const void*, const void*> *InverseMap) const {
171*fa0734ecSArgyrios Kyrtzidis 
172*fa0734ecSArgyrios Kyrtzidis   typedef llvm::DenseSet<const ExplodedNode*> Pass1Ty;
173*fa0734ecSArgyrios Kyrtzidis   Pass1Ty Pass1;
174*fa0734ecSArgyrios Kyrtzidis 
175*fa0734ecSArgyrios Kyrtzidis   typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> Pass2Ty;
176*fa0734ecSArgyrios Kyrtzidis   Pass2Ty& Pass2 = M->M;
177*fa0734ecSArgyrios Kyrtzidis 
178*fa0734ecSArgyrios Kyrtzidis   llvm::SmallVector<const ExplodedNode*, 10> WL1, WL2;
179*fa0734ecSArgyrios Kyrtzidis 
180*fa0734ecSArgyrios Kyrtzidis   // ===- Pass 1 (reverse DFS) -===
181*fa0734ecSArgyrios Kyrtzidis   for (const ExplodedNode* const* I = BeginSources; I != EndSources; ++I) {
182*fa0734ecSArgyrios Kyrtzidis     assert(*I);
183*fa0734ecSArgyrios Kyrtzidis     WL1.push_back(*I);
184*fa0734ecSArgyrios Kyrtzidis   }
185*fa0734ecSArgyrios Kyrtzidis 
186*fa0734ecSArgyrios Kyrtzidis   // Process the first worklist until it is empty.  Because it is a std::list
187*fa0734ecSArgyrios Kyrtzidis   // it acts like a FIFO queue.
188*fa0734ecSArgyrios Kyrtzidis   while (!WL1.empty()) {
189*fa0734ecSArgyrios Kyrtzidis     const ExplodedNode *N = WL1.back();
190*fa0734ecSArgyrios Kyrtzidis     WL1.pop_back();
191*fa0734ecSArgyrios Kyrtzidis 
192*fa0734ecSArgyrios Kyrtzidis     // Have we already visited this node?  If so, continue to the next one.
193*fa0734ecSArgyrios Kyrtzidis     if (Pass1.count(N))
194*fa0734ecSArgyrios Kyrtzidis       continue;
195*fa0734ecSArgyrios Kyrtzidis 
196*fa0734ecSArgyrios Kyrtzidis     // Otherwise, mark this node as visited.
197*fa0734ecSArgyrios Kyrtzidis     Pass1.insert(N);
198*fa0734ecSArgyrios Kyrtzidis 
199*fa0734ecSArgyrios Kyrtzidis     // If this is a root enqueue it to the second worklist.
200*fa0734ecSArgyrios Kyrtzidis     if (N->Preds.empty()) {
201*fa0734ecSArgyrios Kyrtzidis       WL2.push_back(N);
202*fa0734ecSArgyrios Kyrtzidis       continue;
203*fa0734ecSArgyrios Kyrtzidis     }
204*fa0734ecSArgyrios Kyrtzidis 
205*fa0734ecSArgyrios Kyrtzidis     // Visit our predecessors and enqueue them.
206*fa0734ecSArgyrios Kyrtzidis     for (ExplodedNode** I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I)
207*fa0734ecSArgyrios Kyrtzidis       WL1.push_back(*I);
208*fa0734ecSArgyrios Kyrtzidis   }
209*fa0734ecSArgyrios Kyrtzidis 
210*fa0734ecSArgyrios Kyrtzidis   // We didn't hit a root? Return with a null pointer for the new graph.
211*fa0734ecSArgyrios Kyrtzidis   if (WL2.empty())
212*fa0734ecSArgyrios Kyrtzidis     return 0;
213*fa0734ecSArgyrios Kyrtzidis 
214*fa0734ecSArgyrios Kyrtzidis   // Create an empty graph.
215*fa0734ecSArgyrios Kyrtzidis   ExplodedGraph* G = MakeEmptyGraph();
216*fa0734ecSArgyrios Kyrtzidis 
217*fa0734ecSArgyrios Kyrtzidis   // ===- Pass 2 (forward DFS to construct the new graph) -===
218*fa0734ecSArgyrios Kyrtzidis   while (!WL2.empty()) {
219*fa0734ecSArgyrios Kyrtzidis     const ExplodedNode* N = WL2.back();
220*fa0734ecSArgyrios Kyrtzidis     WL2.pop_back();
221*fa0734ecSArgyrios Kyrtzidis 
222*fa0734ecSArgyrios Kyrtzidis     // Skip this node if we have already processed it.
223*fa0734ecSArgyrios Kyrtzidis     if (Pass2.find(N) != Pass2.end())
224*fa0734ecSArgyrios Kyrtzidis       continue;
225*fa0734ecSArgyrios Kyrtzidis 
226*fa0734ecSArgyrios Kyrtzidis     // Create the corresponding node in the new graph and record the mapping
227*fa0734ecSArgyrios Kyrtzidis     // from the old node to the new node.
228*fa0734ecSArgyrios Kyrtzidis     ExplodedNode* NewN = G->getNode(N->getLocation(), N->State, NULL);
229*fa0734ecSArgyrios Kyrtzidis     Pass2[N] = NewN;
230*fa0734ecSArgyrios Kyrtzidis 
231*fa0734ecSArgyrios Kyrtzidis     // Also record the reverse mapping from the new node to the old node.
232*fa0734ecSArgyrios Kyrtzidis     if (InverseMap) (*InverseMap)[NewN] = N;
233*fa0734ecSArgyrios Kyrtzidis 
234*fa0734ecSArgyrios Kyrtzidis     // If this node is a root, designate it as such in the graph.
235*fa0734ecSArgyrios Kyrtzidis     if (N->Preds.empty())
236*fa0734ecSArgyrios Kyrtzidis       G->addRoot(NewN);
237*fa0734ecSArgyrios Kyrtzidis 
238*fa0734ecSArgyrios Kyrtzidis     // In the case that some of the intended predecessors of NewN have already
239*fa0734ecSArgyrios Kyrtzidis     // been created, we should hook them up as predecessors.
240*fa0734ecSArgyrios Kyrtzidis 
241*fa0734ecSArgyrios Kyrtzidis     // Walk through the predecessors of 'N' and hook up their corresponding
242*fa0734ecSArgyrios Kyrtzidis     // nodes in the new graph (if any) to the freshly created node.
243*fa0734ecSArgyrios Kyrtzidis     for (ExplodedNode **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) {
244*fa0734ecSArgyrios Kyrtzidis       Pass2Ty::iterator PI = Pass2.find(*I);
245*fa0734ecSArgyrios Kyrtzidis       if (PI == Pass2.end())
246*fa0734ecSArgyrios Kyrtzidis         continue;
247*fa0734ecSArgyrios Kyrtzidis 
248*fa0734ecSArgyrios Kyrtzidis       NewN->addPredecessor(PI->second, *G);
249*fa0734ecSArgyrios Kyrtzidis     }
250*fa0734ecSArgyrios Kyrtzidis 
251*fa0734ecSArgyrios Kyrtzidis     // In the case that some of the intended successors of NewN have already
252*fa0734ecSArgyrios Kyrtzidis     // been created, we should hook them up as successors.  Otherwise, enqueue
253*fa0734ecSArgyrios Kyrtzidis     // the new nodes from the original graph that should have nodes created
254*fa0734ecSArgyrios Kyrtzidis     // in the new graph.
255*fa0734ecSArgyrios Kyrtzidis     for (ExplodedNode **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) {
256*fa0734ecSArgyrios Kyrtzidis       Pass2Ty::iterator PI = Pass2.find(*I);
257*fa0734ecSArgyrios Kyrtzidis       if (PI != Pass2.end()) {
258*fa0734ecSArgyrios Kyrtzidis         PI->second->addPredecessor(NewN, *G);
259*fa0734ecSArgyrios Kyrtzidis         continue;
260*fa0734ecSArgyrios Kyrtzidis       }
261*fa0734ecSArgyrios Kyrtzidis 
262*fa0734ecSArgyrios Kyrtzidis       // Enqueue nodes to the worklist that were marked during pass 1.
263*fa0734ecSArgyrios Kyrtzidis       if (Pass1.count(*I))
264*fa0734ecSArgyrios Kyrtzidis         WL2.push_back(*I);
265*fa0734ecSArgyrios Kyrtzidis     }
266*fa0734ecSArgyrios Kyrtzidis 
267*fa0734ecSArgyrios Kyrtzidis     // Finally, explictly mark all nodes without any successors as sinks.
268*fa0734ecSArgyrios Kyrtzidis     if (N->isSink())
269*fa0734ecSArgyrios Kyrtzidis       NewN->markAsSink();
270*fa0734ecSArgyrios Kyrtzidis   }
271*fa0734ecSArgyrios Kyrtzidis 
272*fa0734ecSArgyrios Kyrtzidis   return G;
273*fa0734ecSArgyrios Kyrtzidis }
274*fa0734ecSArgyrios Kyrtzidis 
275*fa0734ecSArgyrios Kyrtzidis ExplodedNode*
276*fa0734ecSArgyrios Kyrtzidis InterExplodedGraphMap::getMappedNode(const ExplodedNode* N) const {
277*fa0734ecSArgyrios Kyrtzidis   llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::const_iterator I =
278*fa0734ecSArgyrios Kyrtzidis     M.find(N);
279*fa0734ecSArgyrios Kyrtzidis 
280*fa0734ecSArgyrios Kyrtzidis   return I == M.end() ? 0 : I->second;
281*fa0734ecSArgyrios Kyrtzidis }
282*fa0734ecSArgyrios Kyrtzidis 
283