1 //===- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the template classes ExplodedNode and ExplodedGraph, 10 // which represent a path-sensitive, intra-procedural "exploded graph." 11 // See "Precise interprocedural dataflow analysis via graph reachability" 12 // by Reps, Horwitz, and Sagiv 13 // (http://portal.acm.org/citation.cfm?id=199462) for the definition of an 14 // exploded graph. 15 // 16 //===----------------------------------------------------------------------===// 17 18 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H 19 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H 20 21 #include "clang/Analysis/AnalysisDeclContext.h" 22 #include "clang/Analysis/ProgramPoint.h" 23 #include "clang/Analysis/Support/BumpVector.h" 24 #include "clang/Basic/LLVM.h" 25 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 26 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" 27 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" 28 #include "llvm/ADT/ArrayRef.h" 29 #include "llvm/ADT/DenseMap.h" 30 #include "llvm/ADT/DepthFirstIterator.h" 31 #include "llvm/ADT/FoldingSet.h" 32 #include "llvm/ADT/GraphTraits.h" 33 #include "llvm/ADT/Optional.h" 34 #include "llvm/ADT/STLExtras.h" 35 #include "llvm/ADT/SetVector.h" 36 #include "llvm/Support/Allocator.h" 37 #include "llvm/Support/Compiler.h" 38 #include <cassert> 39 #include <cstdint> 40 #include <memory> 41 #include <utility> 42 #include <vector> 43 44 namespace clang { 45 46 class CFG; 47 class Decl; 48 class Expr; 49 class ParentMap; 50 class Stmt; 51 52 namespace ento { 53 54 class ExplodedGraph; 55 56 //===----------------------------------------------------------------------===// 57 // ExplodedGraph "implementation" classes. These classes are not typed to 58 // contain a specific kind of state. Typed-specialized versions are defined 59 // on top of these classes. 60 //===----------------------------------------------------------------------===// 61 62 // ExplodedNode is not constified all over the engine because we need to add 63 // successors to it at any time after creating it. 64 65 class ExplodedNode : public llvm::FoldingSetNode { 66 friend class BranchNodeBuilder; 67 friend class CoreEngine; 68 friend class EndOfFunctionNodeBuilder; 69 friend class ExplodedGraph; 70 friend class IndirectGotoNodeBuilder; 71 friend class NodeBuilder; 72 friend class SwitchNodeBuilder; 73 74 /// Efficiently stores a list of ExplodedNodes, or an optional flag. 75 /// 76 /// NodeGroup provides opaque storage for a list of ExplodedNodes, optimizing 77 /// for the case when there is only one node in the group. This is a fairly 78 /// common case in an ExplodedGraph, where most nodes have only one 79 /// predecessor and many have only one successor. It can also be used to 80 /// store a flag rather than a node list, which ExplodedNode uses to mark 81 /// whether a node is a sink. If the flag is set, the group is implicitly 82 /// empty and no nodes may be added. 83 class NodeGroup { 84 // Conceptually a discriminated union. If the low bit is set, the node is 85 // a sink. If the low bit is not set, the pointer refers to the storage 86 // for the nodes in the group. 87 // This is not a PointerIntPair in order to keep the storage type opaque. 88 uintptr_t P; 89 90 public: 91 NodeGroup(bool Flag = false) : P(Flag) { 92 assert(getFlag() == Flag); 93 } 94 95 ExplodedNode * const *begin() const; 96 97 ExplodedNode * const *end() const; 98 99 unsigned size() const; 100 101 bool empty() const { return P == 0 || getFlag() != 0; } 102 103 /// Adds a node to the list. 104 /// 105 /// The group must not have been created with its flag set. 106 void addNode(ExplodedNode *N, ExplodedGraph &G); 107 108 /// Replaces the single node in this group with a new node. 109 /// 110 /// Note that this should only be used when you know the group was not 111 /// created with its flag set, and that the group is empty or contains 112 /// only a single node. 113 void replaceNode(ExplodedNode *node); 114 115 /// Returns whether this group was created with its flag set. 116 bool getFlag() const { 117 return (P & 1); 118 } 119 }; 120 121 /// Location - The program location (within a function body) associated 122 /// with this node. 123 const ProgramPoint Location; 124 125 /// State - The state associated with this node. 126 ProgramStateRef State; 127 128 /// Preds - The predecessors of this node. 129 NodeGroup Preds; 130 131 /// Succs - The successors of this node. 132 NodeGroup Succs; 133 134 public: 135 explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state, 136 bool IsSink) 137 : Location(loc), State(std::move(state)), Succs(IsSink) { 138 assert(isSink() == IsSink); 139 } 140 141 /// getLocation - Returns the edge associated with the given node. 142 ProgramPoint getLocation() const { return Location; } 143 144 const LocationContext *getLocationContext() const { 145 return getLocation().getLocationContext(); 146 } 147 148 const StackFrameContext *getStackFrame() const { 149 return getLocation().getStackFrame(); 150 } 151 152 const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); } 153 154 CFG &getCFG() const { return *getLocationContext()->getCFG(); } 155 156 const CFGBlock *getCFGBlock() const; 157 158 const ParentMap &getParentMap() const { 159 return getLocationContext()->getParentMap(); 160 } 161 162 template <typename T> 163 T &getAnalysis() const { 164 return *getLocationContext()->getAnalysis<T>(); 165 } 166 167 const ProgramStateRef &getState() const { return State; } 168 169 template <typename T> 170 Optional<T> getLocationAs() const LLVM_LVALUE_FUNCTION { 171 return Location.getAs<T>(); 172 } 173 174 /// Get the value of an arbitrary expression at this node. 175 SVal getSVal(const Stmt *S) const { 176 return getState()->getSVal(S, getLocationContext()); 177 } 178 179 static void Profile(llvm::FoldingSetNodeID &ID, 180 const ProgramPoint &Loc, 181 const ProgramStateRef &state, 182 bool IsSink) { 183 ID.Add(Loc); 184 ID.AddPointer(state.get()); 185 ID.AddBoolean(IsSink); 186 } 187 188 void Profile(llvm::FoldingSetNodeID& ID) const { 189 // We avoid copy constructors by not using accessors. 190 Profile(ID, Location, State, isSink()); 191 } 192 193 /// addPredeccessor - Adds a predecessor to the current node, and 194 /// in tandem add this node as a successor of the other node. 195 void addPredecessor(ExplodedNode *V, ExplodedGraph &G); 196 197 unsigned succ_size() const { return Succs.size(); } 198 unsigned pred_size() const { return Preds.size(); } 199 bool succ_empty() const { return Succs.empty(); } 200 bool pred_empty() const { return Preds.empty(); } 201 202 bool isSink() const { return Succs.getFlag(); } 203 204 bool hasSinglePred() const { 205 return (pred_size() == 1); 206 } 207 208 ExplodedNode *getFirstPred() { 209 return pred_empty() ? nullptr : *(pred_begin()); 210 } 211 212 const ExplodedNode *getFirstPred() const { 213 return const_cast<ExplodedNode*>(this)->getFirstPred(); 214 } 215 216 ExplodedNode *getFirstSucc() { 217 return succ_empty() ? nullptr : *(succ_begin()); 218 } 219 220 const ExplodedNode *getFirstSucc() const { 221 return const_cast<ExplodedNode*>(this)->getFirstSucc(); 222 } 223 224 // Iterators over successor and predecessor vertices. 225 using succ_iterator = ExplodedNode * const *; 226 using succ_range = llvm::iterator_range<succ_iterator>; 227 228 using const_succ_iterator = const ExplodedNode * const *; 229 using const_succ_range = llvm::iterator_range<const_succ_iterator>; 230 231 using pred_iterator = ExplodedNode * const *; 232 using pred_range = llvm::iterator_range<pred_iterator>; 233 234 using const_pred_iterator = const ExplodedNode * const *; 235 using const_pred_range = llvm::iterator_range<const_pred_iterator>; 236 237 pred_iterator pred_begin() { return Preds.begin(); } 238 pred_iterator pred_end() { return Preds.end(); } 239 pred_range preds() { return {Preds.begin(), Preds.end()}; } 240 241 const_pred_iterator pred_begin() const { 242 return const_cast<ExplodedNode*>(this)->pred_begin(); 243 } 244 const_pred_iterator pred_end() const { 245 return const_cast<ExplodedNode*>(this)->pred_end(); 246 } 247 const_pred_range preds() const { return {Preds.begin(), Preds.end()}; } 248 249 succ_iterator succ_begin() { return Succs.begin(); } 250 succ_iterator succ_end() { return Succs.end(); } 251 succ_range succs() { return {Succs.begin(), Succs.end()}; } 252 253 const_succ_iterator succ_begin() const { 254 return const_cast<ExplodedNode*>(this)->succ_begin(); 255 } 256 const_succ_iterator succ_end() const { 257 return const_cast<ExplodedNode*>(this)->succ_end(); 258 } 259 const_succ_range succs() const { return {Succs.begin(), Succs.end()}; } 260 261 int64_t getID(ExplodedGraph *G) const; 262 263 /// The node is trivial if it has only one successor, only one predecessor, 264 /// it's predecessor has only one successor, 265 /// and its program state is the same as the program state of the previous 266 /// node. 267 /// Trivial nodes may be skipped while printing exploded graph. 268 bool isTrivial() const; 269 270 private: 271 void replaceSuccessor(ExplodedNode *node) { Succs.replaceNode(node); } 272 void replacePredecessor(ExplodedNode *node) { Preds.replaceNode(node); } 273 }; 274 275 using InterExplodedGraphMap = 276 llvm::DenseMap<const ExplodedNode *, const ExplodedNode *>; 277 278 class ExplodedGraph { 279 protected: 280 friend class CoreEngine; 281 282 // Type definitions. 283 using NodeVector = std::vector<ExplodedNode *>; 284 285 /// The roots of the simulation graph. Usually there will be only 286 /// one, but clients are free to establish multiple subgraphs within a single 287 /// SimulGraph. Moreover, these subgraphs can often merge when paths from 288 /// different roots reach the same state at the same program location. 289 NodeVector Roots; 290 291 /// The nodes in the simulation graph which have been 292 /// specially marked as the endpoint of an abstract simulation path. 293 NodeVector EndNodes; 294 295 /// Nodes - The nodes in the graph. 296 llvm::FoldingSet<ExplodedNode> Nodes; 297 298 /// BVC - Allocator and context for allocating nodes and their predecessor 299 /// and successor groups. 300 BumpVectorContext BVC; 301 302 /// NumNodes - The number of nodes in the graph. 303 unsigned NumNodes = 0; 304 305 /// A list of recently allocated nodes that can potentially be recycled. 306 NodeVector ChangedNodes; 307 308 /// A list of nodes that can be reused. 309 NodeVector FreeNodes; 310 311 /// Determines how often nodes are reclaimed. 312 /// 313 /// If this is 0, nodes will never be reclaimed. 314 unsigned ReclaimNodeInterval = 0; 315 316 /// Counter to determine when to reclaim nodes. 317 unsigned ReclaimCounter; 318 319 public: 320 ExplodedGraph(); 321 ~ExplodedGraph(); 322 323 /// Retrieve the node associated with a (Location,State) pair, 324 /// where the 'Location' is a ProgramPoint in the CFG. If no node for 325 /// this pair exists, it is created. IsNew is set to true if 326 /// the node was freshly created. 327 ExplodedNode *getNode(const ProgramPoint &L, ProgramStateRef State, 328 bool IsSink = false, 329 bool* IsNew = nullptr); 330 331 /// Create a node for a (Location, State) pair, 332 /// but don't store it for deduplication later. This 333 /// is useful when copying an already completed 334 /// ExplodedGraph for further processing. 335 ExplodedNode *createUncachedNode(const ProgramPoint &L, 336 ProgramStateRef State, 337 bool IsSink = false); 338 339 std::unique_ptr<ExplodedGraph> MakeEmptyGraph() const { 340 return std::make_unique<ExplodedGraph>(); 341 } 342 343 /// addRoot - Add an untyped node to the set of roots. 344 ExplodedNode *addRoot(ExplodedNode *V) { 345 Roots.push_back(V); 346 return V; 347 } 348 349 /// addEndOfPath - Add an untyped node to the set of EOP nodes. 350 ExplodedNode *addEndOfPath(ExplodedNode *V) { 351 EndNodes.push_back(V); 352 return V; 353 } 354 355 unsigned num_roots() const { return Roots.size(); } 356 unsigned num_eops() const { return EndNodes.size(); } 357 358 bool empty() const { return NumNodes == 0; } 359 unsigned size() const { return NumNodes; } 360 361 void reserve(unsigned NodeCount) { Nodes.reserve(NodeCount); } 362 363 // Iterators. 364 using NodeTy = ExplodedNode; 365 using AllNodesTy = llvm::FoldingSet<ExplodedNode>; 366 using roots_iterator = NodeVector::iterator; 367 using const_roots_iterator = NodeVector::const_iterator; 368 using eop_iterator = NodeVector::iterator; 369 using const_eop_iterator = NodeVector::const_iterator; 370 using node_iterator = AllNodesTy::iterator; 371 using const_node_iterator = AllNodesTy::const_iterator; 372 373 node_iterator nodes_begin() { return Nodes.begin(); } 374 375 node_iterator nodes_end() { return Nodes.end(); } 376 377 const_node_iterator nodes_begin() const { return Nodes.begin(); } 378 379 const_node_iterator nodes_end() const { return Nodes.end(); } 380 381 roots_iterator roots_begin() { return Roots.begin(); } 382 383 roots_iterator roots_end() { return Roots.end(); } 384 385 const_roots_iterator roots_begin() const { return Roots.begin(); } 386 387 const_roots_iterator roots_end() const { return Roots.end(); } 388 389 eop_iterator eop_begin() { return EndNodes.begin(); } 390 391 eop_iterator eop_end() { return EndNodes.end(); } 392 393 const_eop_iterator eop_begin() const { return EndNodes.begin(); } 394 395 const_eop_iterator eop_end() const { return EndNodes.end(); } 396 397 llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); } 398 BumpVectorContext &getNodeAllocator() { return BVC; } 399 400 using NodeMap = llvm::DenseMap<const ExplodedNode *, ExplodedNode *>; 401 402 /// Creates a trimmed version of the graph that only contains paths leading 403 /// to the given nodes. 404 /// 405 /// \param Nodes The nodes which must appear in the final graph. Presumably 406 /// these are end-of-path nodes (i.e. they have no successors). 407 /// \param[out] ForwardMap A optional map from nodes in this graph to nodes in 408 /// the returned graph. 409 /// \param[out] InverseMap An optional map from nodes in the returned graph to 410 /// nodes in this graph. 411 /// \returns The trimmed graph 412 std::unique_ptr<ExplodedGraph> 413 trim(ArrayRef<const NodeTy *> Nodes, 414 InterExplodedGraphMap *ForwardMap = nullptr, 415 InterExplodedGraphMap *InverseMap = nullptr) const; 416 417 /// Enable tracking of recently allocated nodes for potential reclamation 418 /// when calling reclaimRecentlyAllocatedNodes(). 419 void enableNodeReclamation(unsigned Interval) { 420 ReclaimCounter = ReclaimNodeInterval = Interval; 421 } 422 423 /// Reclaim "uninteresting" nodes created since the last time this method 424 /// was called. 425 void reclaimRecentlyAllocatedNodes(); 426 427 /// Returns true if nodes for the given expression kind are always 428 /// kept around. 429 static bool isInterestingLValueExpr(const Expr *Ex); 430 431 private: 432 bool shouldCollect(const ExplodedNode *node); 433 void collectNode(ExplodedNode *node); 434 }; 435 436 class ExplodedNodeSet { 437 using ImplTy = llvm::SmallSetVector<ExplodedNode *, 4>; 438 ImplTy Impl; 439 440 public: 441 ExplodedNodeSet(ExplodedNode *N) { 442 assert(N && !static_cast<ExplodedNode*>(N)->isSink()); 443 Impl.insert(N); 444 } 445 446 ExplodedNodeSet() = default; 447 448 void Add(ExplodedNode *N) { 449 if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N); 450 } 451 452 using iterator = ImplTy::iterator; 453 using const_iterator = ImplTy::const_iterator; 454 455 unsigned size() const { return Impl.size(); } 456 bool empty() const { return Impl.empty(); } 457 bool erase(ExplodedNode *N) { return Impl.remove(N); } 458 459 void clear() { Impl.clear(); } 460 461 void insert(const ExplodedNodeSet &S) { 462 assert(&S != this); 463 if (empty()) 464 Impl = S.Impl; 465 else 466 Impl.insert(S.begin(), S.end()); 467 } 468 469 iterator begin() { return Impl.begin(); } 470 iterator end() { return Impl.end(); } 471 472 const_iterator begin() const { return Impl.begin(); } 473 const_iterator end() const { return Impl.end(); } 474 }; 475 476 } // namespace ento 477 478 } // namespace clang 479 480 // GraphTraits 481 482 namespace llvm { 483 template <> struct GraphTraits<clang::ento::ExplodedGraph *> { 484 using GraphTy = clang::ento::ExplodedGraph *; 485 using NodeRef = clang::ento::ExplodedNode *; 486 using ChildIteratorType = clang::ento::ExplodedNode::succ_iterator; 487 using nodes_iterator = llvm::df_iterator<GraphTy>; 488 489 static NodeRef getEntryNode(const GraphTy G) { 490 return *G->roots_begin(); 491 } 492 493 static bool predecessorOfTrivial(NodeRef N) { 494 return N->succ_size() == 1 && N->getFirstSucc()->isTrivial(); 495 } 496 497 static ChildIteratorType child_begin(NodeRef N) { 498 if (predecessorOfTrivial(N)) 499 return child_begin(*N->succ_begin()); 500 return N->succ_begin(); 501 } 502 503 static ChildIteratorType child_end(NodeRef N) { 504 if (predecessorOfTrivial(N)) 505 return child_end(N->getFirstSucc()); 506 return N->succ_end(); 507 } 508 509 static nodes_iterator nodes_begin(const GraphTy G) { 510 return df_begin(G); 511 } 512 513 static nodes_iterator nodes_end(const GraphTy G) { 514 return df_end(G); 515 } 516 }; 517 } // namespace llvm 518 519 #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H 520