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