Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:37:08

0001 //===- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -----*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 //  This file defines the template classes ExplodedNode and ExplodedGraph,
0010 //  which represent a path-sensitive, intra-procedural "exploded graph."
0011 //  See "Precise interprocedural dataflow analysis via graph reachability"
0012 //  by Reps, Horwitz, and Sagiv
0013 //  (http://portal.acm.org/citation.cfm?id=199462) for the definition of an
0014 //  exploded graph.
0015 //
0016 //===----------------------------------------------------------------------===//
0017 
0018 #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H
0019 #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H
0020 
0021 #include "clang/Analysis/AnalysisDeclContext.h"
0022 #include "clang/Analysis/ProgramPoint.h"
0023 #include "clang/Analysis/Support/BumpVector.h"
0024 #include "clang/Basic/LLVM.h"
0025 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
0026 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
0027 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
0028 #include "llvm/ADT/ArrayRef.h"
0029 #include "llvm/ADT/DenseMap.h"
0030 #include "llvm/ADT/DepthFirstIterator.h"
0031 #include "llvm/ADT/FoldingSet.h"
0032 #include "llvm/ADT/GraphTraits.h"
0033 #include "llvm/ADT/STLExtras.h"
0034 #include "llvm/ADT/SetVector.h"
0035 #include "llvm/ADT/iterator_range.h"
0036 #include "llvm/Support/Allocator.h"
0037 #include "llvm/Support/Compiler.h"
0038 #include <cassert>
0039 #include <cstdint>
0040 #include <memory>
0041 #include <optional>
0042 #include <utility>
0043 #include <vector>
0044 
0045 namespace clang {
0046 
0047 class CFG;
0048 class Decl;
0049 class Expr;
0050 class ParentMap;
0051 class Stmt;
0052 
0053 namespace ento {
0054 
0055 class ExplodedGraph;
0056 
0057 //===----------------------------------------------------------------------===//
0058 // ExplodedGraph "implementation" classes.  These classes are not typed to
0059 // contain a specific kind of state.  Typed-specialized versions are defined
0060 // on top of these classes.
0061 //===----------------------------------------------------------------------===//
0062 
0063 // ExplodedNode is not constified all over the engine because we need to add
0064 // successors to it at any time after creating it.
0065 
0066 class ExplodedNode : public llvm::FoldingSetNode {
0067   friend class BranchNodeBuilder;
0068   friend class CoreEngine;
0069   friend class EndOfFunctionNodeBuilder;
0070   friend class ExplodedGraph;
0071   friend class IndirectGotoNodeBuilder;
0072   friend class NodeBuilder;
0073   friend class SwitchNodeBuilder;
0074 
0075   /// Efficiently stores a list of ExplodedNodes, or an optional flag.
0076   ///
0077   /// NodeGroup provides opaque storage for a list of ExplodedNodes, optimizing
0078   /// for the case when there is only one node in the group. This is a fairly
0079   /// common case in an ExplodedGraph, where most nodes have only one
0080   /// predecessor and many have only one successor. It can also be used to
0081   /// store a flag rather than a node list, which ExplodedNode uses to mark
0082   /// whether a node is a sink. If the flag is set, the group is implicitly
0083   /// empty and no nodes may be added.
0084   class NodeGroup {
0085     // Conceptually a discriminated union. If the low bit is set, the node is
0086     // a sink. If the low bit is not set, the pointer refers to the storage
0087     // for the nodes in the group.
0088     // This is not a PointerIntPair in order to keep the storage type opaque.
0089     uintptr_t P;
0090 
0091   public:
0092     NodeGroup(bool Flag = false) : P(Flag) {
0093       assert(getFlag() == Flag);
0094     }
0095 
0096     ExplodedNode * const *begin() const;
0097 
0098     ExplodedNode * const *end() const;
0099 
0100     unsigned size() const;
0101 
0102     bool empty() const { return P == 0 || getFlag() != 0; }
0103 
0104     /// Adds a node to the list.
0105     ///
0106     /// The group must not have been created with its flag set.
0107     void addNode(ExplodedNode *N, ExplodedGraph &G);
0108 
0109     /// Replaces the single node in this group with a new node.
0110     ///
0111     /// Note that this should only be used when you know the group was not
0112     /// created with its flag set, and that the group is empty or contains
0113     /// only a single node.
0114     void replaceNode(ExplodedNode *node);
0115 
0116     /// Returns whether this group was created with its flag set.
0117     bool getFlag() const {
0118       return (P & 1);
0119     }
0120   };
0121 
0122   /// Location - The program location (within a function body) associated
0123   ///  with this node.
0124   const ProgramPoint Location;
0125 
0126   /// State - The state associated with this node.
0127   ProgramStateRef State;
0128 
0129   /// Preds - The predecessors of this node.
0130   NodeGroup Preds;
0131 
0132   /// Succs - The successors of this node.
0133   NodeGroup Succs;
0134 
0135   int64_t Id;
0136 
0137 public:
0138   explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state,
0139                         int64_t Id, bool IsSink)
0140       : Location(loc), State(std::move(state)), Succs(IsSink), Id(Id) {
0141     assert(isSink() == IsSink);
0142   }
0143 
0144   /// getLocation - Returns the edge associated with the given node.
0145   ProgramPoint getLocation() const { return Location; }
0146 
0147   const LocationContext *getLocationContext() const {
0148     return getLocation().getLocationContext();
0149   }
0150 
0151   const StackFrameContext *getStackFrame() const {
0152     return getLocation().getStackFrame();
0153   }
0154 
0155   const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); }
0156 
0157   CFG &getCFG() const { return *getLocationContext()->getCFG(); }
0158 
0159   const CFGBlock *getCFGBlock() const;
0160 
0161   const ParentMap &getParentMap() const {
0162     return getLocationContext()->getParentMap();
0163   }
0164 
0165   template <typename T> T &getAnalysis() const {
0166     return *getLocationContext()->getAnalysis<T>();
0167   }
0168 
0169   const ProgramStateRef &getState() const { return State; }
0170 
0171   template <typename T> std::optional<T> getLocationAs() const & {
0172     return Location.getAs<T>();
0173   }
0174 
0175   /// Get the value of an arbitrary expression at this node.
0176   SVal getSVal(const Stmt *S) const {
0177     return getState()->getSVal(S, getLocationContext());
0178   }
0179 
0180   static void Profile(llvm::FoldingSetNodeID &ID,
0181                       const ProgramPoint &Loc,
0182                       const ProgramStateRef &state,
0183                       bool IsSink) {
0184     ID.Add(Loc);
0185     ID.AddPointer(state.get());
0186     ID.AddBoolean(IsSink);
0187   }
0188 
0189   void Profile(llvm::FoldingSetNodeID& ID) const {
0190     // We avoid copy constructors by not using accessors.
0191     Profile(ID, Location, State, isSink());
0192   }
0193 
0194   /// addPredeccessor - Adds a predecessor to the current node, and
0195   ///  in tandem add this node as a successor of the other node.
0196   void addPredecessor(ExplodedNode *V, ExplodedGraph &G);
0197 
0198   unsigned succ_size() const { return Succs.size(); }
0199   unsigned pred_size() const { return Preds.size(); }
0200   bool succ_empty() const { return Succs.empty(); }
0201   bool pred_empty() const { return Preds.empty(); }
0202 
0203   bool isSink() const { return Succs.getFlag(); }
0204 
0205   bool hasSinglePred() const {
0206     return (pred_size() == 1);
0207   }
0208 
0209   ExplodedNode *getFirstPred() {
0210     return pred_empty() ? nullptr : *(pred_begin());
0211   }
0212 
0213   const ExplodedNode *getFirstPred() const {
0214     return const_cast<ExplodedNode*>(this)->getFirstPred();
0215   }
0216 
0217   ExplodedNode *getFirstSucc() {
0218     return succ_empty() ? nullptr : *(succ_begin());
0219   }
0220 
0221   const ExplodedNode *getFirstSucc() const {
0222     return const_cast<ExplodedNode*>(this)->getFirstSucc();
0223   }
0224 
0225   // Iterators over successor and predecessor vertices.
0226   using succ_iterator = ExplodedNode * const *;
0227   using succ_range = llvm::iterator_range<succ_iterator>;
0228 
0229   using const_succ_iterator = const ExplodedNode * const *;
0230   using const_succ_range = llvm::iterator_range<const_succ_iterator>;
0231 
0232   using pred_iterator = ExplodedNode * const *;
0233   using pred_range = llvm::iterator_range<pred_iterator>;
0234 
0235   using const_pred_iterator = const ExplodedNode * const *;
0236   using const_pred_range = llvm::iterator_range<const_pred_iterator>;
0237 
0238   pred_iterator pred_begin() { return Preds.begin(); }
0239   pred_iterator pred_end() { return Preds.end(); }
0240   pred_range preds() { return {Preds.begin(), Preds.end()}; }
0241 
0242   const_pred_iterator pred_begin() const {
0243     return const_cast<ExplodedNode*>(this)->pred_begin();
0244   }
0245   const_pred_iterator pred_end() const {
0246     return const_cast<ExplodedNode*>(this)->pred_end();
0247   }
0248   const_pred_range preds() const { return {Preds.begin(), Preds.end()}; }
0249 
0250   succ_iterator succ_begin() { return Succs.begin(); }
0251   succ_iterator succ_end() { return Succs.end(); }
0252   succ_range succs() { return {Succs.begin(), Succs.end()}; }
0253 
0254   const_succ_iterator succ_begin() const {
0255     return const_cast<ExplodedNode*>(this)->succ_begin();
0256   }
0257   const_succ_iterator succ_end() const {
0258     return const_cast<ExplodedNode*>(this)->succ_end();
0259   }
0260   const_succ_range succs() const { return {Succs.begin(), Succs.end()}; }
0261 
0262   int64_t getID() const { return Id; }
0263 
0264   /// The node is trivial if it has only one successor, only one predecessor,
0265   /// it's predecessor has only one successor,
0266   /// and its program state is the same as the program state of the previous
0267   /// node.
0268   /// Trivial nodes may be skipped while printing exploded graph.
0269   bool isTrivial() const;
0270 
0271   /// If the node's program point corresponds to a statement, retrieve that
0272   /// statement. Useful for figuring out where to put a warning or a note.
0273   /// If the statement belongs to a body-farmed definition,
0274   /// retrieve the call site for that definition.
0275   const Stmt *getStmtForDiagnostics() const;
0276 
0277   /// Find the next statement that was executed on this node's execution path.
0278   /// Useful for explaining control flow that follows the current node.
0279   /// If the statement belongs to a body-farmed definition, retrieve the
0280   /// call site for that definition.
0281   const Stmt *getNextStmtForDiagnostics() const;
0282 
0283   /// Find the statement that was executed immediately before this node.
0284   /// Useful when the node corresponds to a CFG block entrance.
0285   /// If the statement belongs to a body-farmed definition, retrieve the
0286   /// call site for that definition.
0287   const Stmt *getPreviousStmtForDiagnostics() const;
0288 
0289   /// Find the statement that was executed at or immediately before this node.
0290   /// Useful when any nearby statement will do.
0291   /// If the statement belongs to a body-farmed definition, retrieve the
0292   /// call site for that definition.
0293   const Stmt *getCurrentOrPreviousStmtForDiagnostics() const;
0294 
0295 private:
0296   void replaceSuccessor(ExplodedNode *node) { Succs.replaceNode(node); }
0297   void replacePredecessor(ExplodedNode *node) { Preds.replaceNode(node); }
0298 };
0299 
0300 using InterExplodedGraphMap =
0301     llvm::DenseMap<const ExplodedNode *, const ExplodedNode *>;
0302 
0303 class ExplodedGraph {
0304 protected:
0305   friend class CoreEngine;
0306 
0307   // Type definitions.
0308   using NodeVector = std::vector<ExplodedNode *>;
0309 
0310   /// The roots of the simulation graph. Usually there will be only
0311   /// one, but clients are free to establish multiple subgraphs within a single
0312   /// SimulGraph. Moreover, these subgraphs can often merge when paths from
0313   /// different roots reach the same state at the same program location.
0314   NodeVector Roots;
0315 
0316   /// The nodes in the simulation graph which have been
0317   /// specially marked as the endpoint of an abstract simulation path.
0318   NodeVector EndNodes;
0319 
0320   /// Nodes - The nodes in the graph.
0321   llvm::FoldingSet<ExplodedNode> Nodes;
0322 
0323   /// BVC - Allocator and context for allocating nodes and their predecessor
0324   /// and successor groups.
0325   BumpVectorContext BVC;
0326 
0327   /// NumNodes - The number of nodes in the graph.
0328   int64_t NumNodes = 0;
0329 
0330   /// A list of recently allocated nodes that can potentially be recycled.
0331   NodeVector ChangedNodes;
0332 
0333   /// A list of nodes that can be reused.
0334   NodeVector FreeNodes;
0335 
0336   /// Determines how often nodes are reclaimed.
0337   ///
0338   /// If this is 0, nodes will never be reclaimed.
0339   unsigned ReclaimNodeInterval = 0;
0340 
0341   /// Counter to determine when to reclaim nodes.
0342   unsigned ReclaimCounter;
0343 
0344 public:
0345   ExplodedGraph();
0346   ~ExplodedGraph();
0347 
0348   /// Retrieve the node associated with a (Location,State) pair,
0349   ///  where the 'Location' is a ProgramPoint in the CFG.  If no node for
0350   ///  this pair exists, it is created. IsNew is set to true if
0351   ///  the node was freshly created.
0352   ExplodedNode *getNode(const ProgramPoint &L, ProgramStateRef State,
0353                         bool IsSink = false,
0354                         bool* IsNew = nullptr);
0355 
0356   /// Create a node for a (Location, State) pair,
0357   ///  but don't store it for deduplication later.  This
0358   ///  is useful when copying an already completed
0359   ///  ExplodedGraph for further processing.
0360   ExplodedNode *createUncachedNode(const ProgramPoint &L,
0361     ProgramStateRef State,
0362     int64_t Id,
0363     bool IsSink = false);
0364 
0365   std::unique_ptr<ExplodedGraph> MakeEmptyGraph() const {
0366     return std::make_unique<ExplodedGraph>();
0367   }
0368 
0369   /// addRoot - Add an untyped node to the set of roots.
0370   ExplodedNode *addRoot(ExplodedNode *V) {
0371     Roots.push_back(V);
0372     return V;
0373   }
0374 
0375   /// addEndOfPath - Add an untyped node to the set of EOP nodes.
0376   ExplodedNode *addEndOfPath(ExplodedNode *V) {
0377     EndNodes.push_back(V);
0378     return V;
0379   }
0380 
0381   unsigned num_roots() const { return Roots.size(); }
0382   unsigned num_eops() const { return EndNodes.size(); }
0383 
0384   bool empty() const { return NumNodes == 0; }
0385   unsigned size() const { return NumNodes; }
0386 
0387   void reserve(unsigned NodeCount) { Nodes.reserve(NodeCount); }
0388 
0389   // Iterators.
0390   using NodeTy = ExplodedNode;
0391   using AllNodesTy = llvm::FoldingSet<ExplodedNode>;
0392   using roots_iterator = NodeVector::iterator;
0393   using const_roots_iterator = NodeVector::const_iterator;
0394   using eop_iterator = NodeVector::iterator;
0395   using const_eop_iterator = NodeVector::const_iterator;
0396   using node_iterator = AllNodesTy::iterator;
0397   using const_node_iterator = AllNodesTy::const_iterator;
0398 
0399   llvm::iterator_range<node_iterator> nodes() { return Nodes; }
0400 
0401   llvm::iterator_range<const_node_iterator> nodes() const { return Nodes; }
0402 
0403   roots_iterator roots_begin() { return Roots.begin(); }
0404 
0405   roots_iterator roots_end() { return Roots.end(); }
0406 
0407   const_roots_iterator roots_begin() const { return Roots.begin(); }
0408 
0409   const_roots_iterator roots_end() const { return Roots.end(); }
0410 
0411   eop_iterator eop_begin() { return EndNodes.begin(); }
0412 
0413   eop_iterator eop_end() { return EndNodes.end(); }
0414 
0415   const_eop_iterator eop_begin() const { return EndNodes.begin(); }
0416 
0417   const_eop_iterator eop_end() const { return EndNodes.end(); }
0418 
0419   llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); }
0420   BumpVectorContext &getNodeAllocator() { return BVC; }
0421 
0422   using NodeMap = llvm::DenseMap<const ExplodedNode *, ExplodedNode *>;
0423 
0424   /// Creates a trimmed version of the graph that only contains paths leading
0425   /// to the given nodes.
0426   ///
0427   /// \param Nodes The nodes which must appear in the final graph. Presumably
0428   ///              these are end-of-path nodes (i.e. they have no successors).
0429   /// \param[out] ForwardMap A optional map from nodes in this graph to nodes in
0430   ///                        the returned graph.
0431   /// \param[out] InverseMap An optional map from nodes in the returned graph to
0432   ///                        nodes in this graph.
0433   /// \returns The trimmed graph
0434   std::unique_ptr<ExplodedGraph>
0435   trim(ArrayRef<const NodeTy *> Nodes,
0436        InterExplodedGraphMap *ForwardMap = nullptr,
0437        InterExplodedGraphMap *InverseMap = nullptr) const;
0438 
0439   /// Enable tracking of recently allocated nodes for potential reclamation
0440   /// when calling reclaimRecentlyAllocatedNodes().
0441   void enableNodeReclamation(unsigned Interval) {
0442     ReclaimCounter = ReclaimNodeInterval = Interval;
0443   }
0444 
0445   /// Reclaim "uninteresting" nodes created since the last time this method
0446   /// was called.
0447   void reclaimRecentlyAllocatedNodes();
0448 
0449   /// Returns true if nodes for the given expression kind are always
0450   ///        kept around.
0451   static bool isInterestingLValueExpr(const Expr *Ex);
0452 
0453 private:
0454   bool shouldCollect(const ExplodedNode *node);
0455   void collectNode(ExplodedNode *node);
0456 };
0457 
0458 class ExplodedNodeSet {
0459   using ImplTy = llvm::SmallSetVector<ExplodedNode *, 4>;
0460   ImplTy Impl;
0461 
0462 public:
0463   ExplodedNodeSet(ExplodedNode *N) {
0464     assert(N && !static_cast<ExplodedNode*>(N)->isSink());
0465     Impl.insert(N);
0466   }
0467 
0468   ExplodedNodeSet() = default;
0469 
0470   void Add(ExplodedNode *N) {
0471     if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N);
0472   }
0473 
0474   using iterator = ImplTy::iterator;
0475   using const_iterator = ImplTy::const_iterator;
0476 
0477   unsigned size() const { return Impl.size();  }
0478   bool empty()    const { return Impl.empty(); }
0479   bool erase(ExplodedNode *N) { return Impl.remove(N); }
0480 
0481   void clear() { Impl.clear(); }
0482 
0483   void insert(const ExplodedNodeSet &S) {
0484     assert(&S != this);
0485     if (empty())
0486       Impl = S.Impl;
0487     else
0488       Impl.insert(S.begin(), S.end());
0489   }
0490 
0491   iterator begin() { return Impl.begin(); }
0492   iterator end() { return Impl.end(); }
0493 
0494   const_iterator begin() const { return Impl.begin(); }
0495   const_iterator end() const { return Impl.end(); }
0496 };
0497 
0498 } // namespace ento
0499 
0500 } // namespace clang
0501 
0502 // GraphTraits
0503 
0504 namespace llvm {
0505   template <> struct GraphTraits<clang::ento::ExplodedGraph *> {
0506     using GraphTy = clang::ento::ExplodedGraph *;
0507     using NodeRef = clang::ento::ExplodedNode *;
0508     using ChildIteratorType = clang::ento::ExplodedNode::succ_iterator;
0509     using nodes_iterator = llvm::df_iterator<GraphTy>;
0510 
0511     static NodeRef getEntryNode(const GraphTy G) {
0512       return *G->roots_begin();
0513     }
0514 
0515     static bool predecessorOfTrivial(NodeRef N) {
0516       return N->succ_size() == 1 && N->getFirstSucc()->isTrivial();
0517     }
0518 
0519     static ChildIteratorType child_begin(NodeRef N) {
0520       if (predecessorOfTrivial(N))
0521         return child_begin(*N->succ_begin());
0522       return N->succ_begin();
0523     }
0524 
0525     static ChildIteratorType child_end(NodeRef N) {
0526       if (predecessorOfTrivial(N))
0527         return child_end(N->getFirstSucc());
0528       return N->succ_end();
0529     }
0530 
0531     static nodes_iterator nodes_begin(const GraphTy G) {
0532       return df_begin(G);
0533     }
0534 
0535     static nodes_iterator nodes_end(const GraphTy G) {
0536       return df_end(G);
0537     }
0538   };
0539 } // namespace llvm
0540 
0541 #endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H