clang API Documentation

ExplodedGraph.cpp
Go to the documentation of this file.
00001 //=-- ExplodedGraph.cpp - Local, Path-Sens. "Exploded Graph" -*- C++ -*------=//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 //  This file defines the template classes ExplodedNode and ExplodedGraph,
00011 //  which represent a path-sensitive, intra-procedural "exploded graph."
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
00016 #include "clang/AST/ParentMap.h"
00017 #include "clang/AST/Stmt.h"
00018 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
00019 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
00020 #include "llvm/ADT/DenseMap.h"
00021 #include "llvm/ADT/DenseSet.h"
00022 #include "llvm/ADT/SmallVector.h"
00023 #include "llvm/ADT/Statistic.h"
00024 #include <vector>
00025 
00026 using namespace clang;
00027 using namespace ento;
00028 
00029 //===----------------------------------------------------------------------===//
00030 // Node auditing.
00031 //===----------------------------------------------------------------------===//
00032 
00033 // An out of line virtual method to provide a home for the class vtable.
00034 ExplodedNode::Auditor::~Auditor() {}
00035 
00036 #ifndef NDEBUG
00037 static ExplodedNode::Auditor* NodeAuditor = nullptr;
00038 #endif
00039 
00040 void ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) {
00041 #ifndef NDEBUG
00042   NodeAuditor = A;
00043 #endif
00044 }
00045 
00046 //===----------------------------------------------------------------------===//
00047 // Cleanup.
00048 //===----------------------------------------------------------------------===//
00049 
00050 ExplodedGraph::ExplodedGraph()
00051   : NumNodes(0), ReclaimNodeInterval(0) {}
00052 
00053 ExplodedGraph::~ExplodedGraph() {}
00054 
00055 //===----------------------------------------------------------------------===//
00056 // Node reclamation.
00057 //===----------------------------------------------------------------------===//
00058 
00059 bool ExplodedGraph::isInterestingLValueExpr(const Expr *Ex) {
00060   if (!Ex->isLValue())
00061     return false;
00062   return isa<DeclRefExpr>(Ex) ||
00063          isa<MemberExpr>(Ex) ||
00064          isa<ObjCIvarRefExpr>(Ex);
00065 }
00066 
00067 bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
00068   // First, we only consider nodes for reclamation of the following
00069   // conditions apply:
00070   //
00071   // (1) 1 predecessor (that has one successor)
00072   // (2) 1 successor (that has one predecessor)
00073   //
00074   // If a node has no successor it is on the "frontier", while a node
00075   // with no predecessor is a root.
00076   //
00077   // After these prerequisites, we discard all "filler" nodes that
00078   // are used only for intermediate processing, and are not essential
00079   // for analyzer history:
00080   //
00081   // (a) PreStmtPurgeDeadSymbols
00082   //
00083   // We then discard all other nodes where *all* of the following conditions
00084   // apply:
00085   //
00086   // (3) The ProgramPoint is for a PostStmt, but not a PostStore.
00087   // (4) There is no 'tag' for the ProgramPoint.
00088   // (5) The 'store' is the same as the predecessor.
00089   // (6) The 'GDM' is the same as the predecessor.
00090   // (7) The LocationContext is the same as the predecessor.
00091   // (8) Expressions that are *not* lvalue expressions.
00092   // (9) The PostStmt isn't for a non-consumed Stmt or Expr.
00093   // (10) The successor is neither a CallExpr StmtPoint nor a CallEnter or 
00094   //      PreImplicitCall (so that we would be able to find it when retrying a 
00095   //      call with no inlining).
00096   // FIXME: It may be safe to reclaim PreCall and PostCall nodes as well.
00097 
00098   // Conditions 1 and 2.
00099   if (node->pred_size() != 1 || node->succ_size() != 1)
00100     return false;
00101 
00102   const ExplodedNode *pred = *(node->pred_begin());
00103   if (pred->succ_size() != 1)
00104     return false;
00105   
00106   const ExplodedNode *succ = *(node->succ_begin());
00107   if (succ->pred_size() != 1)
00108     return false;
00109 
00110   // Now reclaim any nodes that are (by definition) not essential to
00111   // analysis history and are not consulted by any client code.
00112   ProgramPoint progPoint = node->getLocation();
00113   if (progPoint.getAs<PreStmtPurgeDeadSymbols>())
00114     return !progPoint.getTag();
00115 
00116   // Condition 3.
00117   if (!progPoint.getAs<PostStmt>() || progPoint.getAs<PostStore>())
00118     return false;
00119 
00120   // Condition 4.
00121   if (progPoint.getTag())
00122     return false;
00123 
00124   // Conditions 5, 6, and 7.
00125   ProgramStateRef state = node->getState();
00126   ProgramStateRef pred_state = pred->getState();    
00127   if (state->store != pred_state->store || state->GDM != pred_state->GDM ||
00128       progPoint.getLocationContext() != pred->getLocationContext())
00129     return false;
00130 
00131   // All further checks require expressions. As per #3, we know that we have
00132   // a PostStmt.
00133   const Expr *Ex = dyn_cast<Expr>(progPoint.castAs<PostStmt>().getStmt());
00134   if (!Ex)
00135     return false;
00136 
00137   // Condition 8.
00138   // Do not collect nodes for "interesting" lvalue expressions since they are
00139   // used extensively for generating path diagnostics.
00140   if (isInterestingLValueExpr(Ex))
00141     return false;
00142 
00143   // Condition 9.
00144   // Do not collect nodes for non-consumed Stmt or Expr to ensure precise
00145   // diagnostic generation; specifically, so that we could anchor arrows
00146   // pointing to the beginning of statements (as written in code).
00147   ParentMap &PM = progPoint.getLocationContext()->getParentMap();
00148   if (!PM.isConsumedExpr(Ex))
00149     return false;
00150 
00151   // Condition 10.
00152   const ProgramPoint SuccLoc = succ->getLocation();
00153   if (Optional<StmtPoint> SP = SuccLoc.getAs<StmtPoint>())
00154     if (CallEvent::isCallStmt(SP->getStmt()))
00155       return false;
00156 
00157   // Condition 10, continuation.
00158   if (SuccLoc.getAs<CallEnter>() || SuccLoc.getAs<PreImplicitCall>())
00159     return false;
00160 
00161   return true;
00162 }
00163 
00164 void ExplodedGraph::collectNode(ExplodedNode *node) {
00165   // Removing a node means:
00166   // (a) changing the predecessors successor to the successor of this node
00167   // (b) changing the successors predecessor to the predecessor of this node
00168   // (c) Putting 'node' onto freeNodes.
00169   assert(node->pred_size() == 1 || node->succ_size() == 1);
00170   ExplodedNode *pred = *(node->pred_begin());
00171   ExplodedNode *succ = *(node->succ_begin());
00172   pred->replaceSuccessor(succ);
00173   succ->replacePredecessor(pred);
00174   FreeNodes.push_back(node);
00175   Nodes.RemoveNode(node);
00176   --NumNodes;
00177   node->~ExplodedNode();  
00178 }
00179 
00180 void ExplodedGraph::reclaimRecentlyAllocatedNodes() {
00181   if (ChangedNodes.empty())
00182     return;
00183 
00184   // Only periodically reclaim nodes so that we can build up a set of
00185   // nodes that meet the reclamation criteria.  Freshly created nodes
00186   // by definition have no successor, and thus cannot be reclaimed (see below).
00187   assert(ReclaimCounter > 0);
00188   if (--ReclaimCounter != 0)
00189     return;
00190   ReclaimCounter = ReclaimNodeInterval;
00191 
00192   for (NodeVector::iterator it = ChangedNodes.begin(), et = ChangedNodes.end();
00193        it != et; ++it) {
00194     ExplodedNode *node = *it;
00195     if (shouldCollect(node))
00196       collectNode(node);
00197   }
00198   ChangedNodes.clear();
00199 }
00200 
00201 //===----------------------------------------------------------------------===//
00202 // ExplodedNode.
00203 //===----------------------------------------------------------------------===//
00204 
00205 // An NodeGroup's storage type is actually very much like a TinyPtrVector:
00206 // it can be either a pointer to a single ExplodedNode, or a pointer to a
00207 // BumpVector allocated with the ExplodedGraph's allocator. This allows the
00208 // common case of single-node NodeGroups to be implemented with no extra memory.
00209 //
00210 // Consequently, each of the NodeGroup methods have up to four cases to handle:
00211 // 1. The flag is set and this group does not actually contain any nodes.
00212 // 2. The group is empty, in which case the storage value is null.
00213 // 3. The group contains a single node.
00214 // 4. The group contains more than one node.
00215 typedef BumpVector<ExplodedNode *> ExplodedNodeVector;
00216 typedef llvm::PointerUnion<ExplodedNode *, ExplodedNodeVector *> GroupStorage;
00217 
00218 void ExplodedNode::addPredecessor(ExplodedNode *V, ExplodedGraph &G) {
00219   assert (!V->isSink());
00220   Preds.addNode(V, G);
00221   V->Succs.addNode(this, G);
00222 #ifndef NDEBUG
00223   if (NodeAuditor) NodeAuditor->AddEdge(V, this);
00224 #endif
00225 }
00226 
00227 void ExplodedNode::NodeGroup::replaceNode(ExplodedNode *node) {
00228   assert(!getFlag());
00229 
00230   GroupStorage &Storage = reinterpret_cast<GroupStorage&>(P);
00231   assert(Storage.is<ExplodedNode *>());
00232   Storage = node;
00233   assert(Storage.is<ExplodedNode *>());
00234 }
00235 
00236 void ExplodedNode::NodeGroup::addNode(ExplodedNode *N, ExplodedGraph &G) {
00237   assert(!getFlag());
00238 
00239   GroupStorage &Storage = reinterpret_cast<GroupStorage&>(P);
00240   if (Storage.isNull()) {
00241     Storage = N;
00242     assert(Storage.is<ExplodedNode *>());
00243     return;
00244   }
00245 
00246   ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>();
00247 
00248   if (!V) {
00249     // Switch from single-node to multi-node representation.
00250     ExplodedNode *Old = Storage.get<ExplodedNode *>();
00251 
00252     BumpVectorContext &Ctx = G.getNodeAllocator();
00253     V = G.getAllocator().Allocate<ExplodedNodeVector>();
00254     new (V) ExplodedNodeVector(Ctx, 4);
00255     V->push_back(Old, Ctx);
00256 
00257     Storage = V;
00258     assert(!getFlag());
00259     assert(Storage.is<ExplodedNodeVector *>());
00260   }
00261 
00262   V->push_back(N, G.getNodeAllocator());
00263 }
00264 
00265 unsigned ExplodedNode::NodeGroup::size() const {
00266   if (getFlag())
00267     return 0;
00268 
00269   const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P);
00270   if (Storage.isNull())
00271     return 0;
00272   if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>())
00273     return V->size();
00274   return 1;
00275 }
00276 
00277 ExplodedNode * const *ExplodedNode::NodeGroup::begin() const {
00278   if (getFlag())
00279     return nullptr;
00280 
00281   const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P);
00282   if (Storage.isNull())
00283     return nullptr;
00284   if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>())
00285     return V->begin();
00286   return Storage.getAddrOfPtr1();
00287 }
00288 
00289 ExplodedNode * const *ExplodedNode::NodeGroup::end() const {
00290   if (getFlag())
00291     return nullptr;
00292 
00293   const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P);
00294   if (Storage.isNull())
00295     return nullptr;
00296   if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>())
00297     return V->end();
00298   return Storage.getAddrOfPtr1() + 1;
00299 }
00300 
00301 ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L,
00302                                      ProgramStateRef State,
00303                                      bool IsSink,
00304                                      bool* IsNew) {
00305   // Profile 'State' to determine if we already have an existing node.
00306   llvm::FoldingSetNodeID profile;
00307   void *InsertPos = nullptr;
00308 
00309   NodeTy::Profile(profile, L, State, IsSink);
00310   NodeTy* V = Nodes.FindNodeOrInsertPos(profile, InsertPos);
00311 
00312   if (!V) {
00313     if (!FreeNodes.empty()) {
00314       V = FreeNodes.back();
00315       FreeNodes.pop_back();
00316     }
00317     else {
00318       // Allocate a new node.
00319       V = (NodeTy*) getAllocator().Allocate<NodeTy>();
00320     }
00321 
00322     new (V) NodeTy(L, State, IsSink);
00323 
00324     if (ReclaimNodeInterval)
00325       ChangedNodes.push_back(V);
00326 
00327     // Insert the node into the node set and return it.
00328     Nodes.InsertNode(V, InsertPos);
00329     ++NumNodes;
00330 
00331     if (IsNew) *IsNew = true;
00332   }
00333   else
00334     if (IsNew) *IsNew = false;
00335 
00336   return V;
00337 }
00338 
00339 std::unique_ptr<ExplodedGraph>
00340 ExplodedGraph::trim(ArrayRef<const NodeTy *> Sinks,
00341                     InterExplodedGraphMap *ForwardMap,
00342                     InterExplodedGraphMap *InverseMap) const {
00343 
00344   if (Nodes.empty())
00345     return nullptr;
00346 
00347   typedef llvm::DenseSet<const ExplodedNode*> Pass1Ty;
00348   Pass1Ty Pass1;
00349 
00350   typedef InterExplodedGraphMap Pass2Ty;
00351   InterExplodedGraphMap Pass2Scratch;
00352   Pass2Ty &Pass2 = ForwardMap ? *ForwardMap : Pass2Scratch;
00353 
00354   SmallVector<const ExplodedNode*, 10> WL1, WL2;
00355 
00356   // ===- Pass 1 (reverse DFS) -===
00357   for (ArrayRef<const NodeTy *>::iterator I = Sinks.begin(), E = Sinks.end();
00358        I != E; ++I) {
00359     if (*I)
00360       WL1.push_back(*I);
00361   }
00362 
00363   // Process the first worklist until it is empty.
00364   while (!WL1.empty()) {
00365     const ExplodedNode *N = WL1.pop_back_val();
00366 
00367     // Have we already visited this node?  If so, continue to the next one.
00368     if (!Pass1.insert(N).second)
00369       continue;
00370 
00371     // If this is a root enqueue it to the second worklist.
00372     if (N->Preds.empty()) {
00373       WL2.push_back(N);
00374       continue;
00375     }
00376 
00377     // Visit our predecessors and enqueue them.
00378     WL1.append(N->Preds.begin(), N->Preds.end());
00379   }
00380 
00381   // We didn't hit a root? Return with a null pointer for the new graph.
00382   if (WL2.empty())
00383     return nullptr;
00384 
00385   // Create an empty graph.
00386   std::unique_ptr<ExplodedGraph> G = MakeEmptyGraph();
00387 
00388   // ===- Pass 2 (forward DFS to construct the new graph) -===
00389   while (!WL2.empty()) {
00390     const ExplodedNode *N = WL2.pop_back_val();
00391 
00392     // Skip this node if we have already processed it.
00393     if (Pass2.find(N) != Pass2.end())
00394       continue;
00395 
00396     // Create the corresponding node in the new graph and record the mapping
00397     // from the old node to the new node.
00398     ExplodedNode *NewN = G->getNode(N->getLocation(), N->State, N->isSink(),
00399                                     nullptr);
00400     Pass2[N] = NewN;
00401 
00402     // Also record the reverse mapping from the new node to the old node.
00403     if (InverseMap) (*InverseMap)[NewN] = N;
00404 
00405     // If this node is a root, designate it as such in the graph.
00406     if (N->Preds.empty())
00407       G->addRoot(NewN);
00408 
00409     // In the case that some of the intended predecessors of NewN have already
00410     // been created, we should hook them up as predecessors.
00411 
00412     // Walk through the predecessors of 'N' and hook up their corresponding
00413     // nodes in the new graph (if any) to the freshly created node.
00414     for (ExplodedNode::pred_iterator I = N->Preds.begin(), E = N->Preds.end();
00415          I != E; ++I) {
00416       Pass2Ty::iterator PI = Pass2.find(*I);
00417       if (PI == Pass2.end())
00418         continue;
00419 
00420       NewN->addPredecessor(const_cast<ExplodedNode *>(PI->second), *G);
00421     }
00422 
00423     // In the case that some of the intended successors of NewN have already
00424     // been created, we should hook them up as successors.  Otherwise, enqueue
00425     // the new nodes from the original graph that should have nodes created
00426     // in the new graph.
00427     for (ExplodedNode::succ_iterator I = N->Succs.begin(), E = N->Succs.end();
00428          I != E; ++I) {
00429       Pass2Ty::iterator PI = Pass2.find(*I);
00430       if (PI != Pass2.end()) {
00431         const_cast<ExplodedNode *>(PI->second)->addPredecessor(NewN, *G);
00432         continue;
00433       }
00434 
00435       // Enqueue nodes to the worklist that were marked during pass 1.
00436       if (Pass1.count(*I))
00437         WL2.push_back(*I);
00438     }
00439   }
00440 
00441   return G;
00442 }
00443