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