File indexing completed on 2026-05-10 08:37:08
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
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
0059
0060
0061
0062
0063
0064
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
0076
0077
0078
0079
0080
0081
0082
0083
0084 class NodeGroup {
0085
0086
0087
0088
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
0105
0106
0107 void addNode(ExplodedNode *N, ExplodedGraph &G);
0108
0109
0110
0111
0112
0113
0114 void replaceNode(ExplodedNode *node);
0115
0116
0117 bool getFlag() const {
0118 return (P & 1);
0119 }
0120 };
0121
0122
0123
0124 const ProgramPoint Location;
0125
0126
0127 ProgramStateRef State;
0128
0129
0130 NodeGroup Preds;
0131
0132
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
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
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
0191 Profile(ID, Location, State, isSink());
0192 }
0193
0194
0195
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
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
0265
0266
0267
0268
0269 bool isTrivial() const;
0270
0271
0272
0273
0274
0275 const Stmt *getStmtForDiagnostics() const;
0276
0277
0278
0279
0280
0281 const Stmt *getNextStmtForDiagnostics() const;
0282
0283
0284
0285
0286
0287 const Stmt *getPreviousStmtForDiagnostics() const;
0288
0289
0290
0291
0292
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
0308 using NodeVector = std::vector<ExplodedNode *>;
0309
0310
0311
0312
0313
0314 NodeVector Roots;
0315
0316
0317
0318 NodeVector EndNodes;
0319
0320
0321 llvm::FoldingSet<ExplodedNode> Nodes;
0322
0323
0324
0325 BumpVectorContext BVC;
0326
0327
0328 int64_t NumNodes = 0;
0329
0330
0331 NodeVector ChangedNodes;
0332
0333
0334 NodeVector FreeNodes;
0335
0336
0337
0338
0339 unsigned ReclaimNodeInterval = 0;
0340
0341
0342 unsigned ReclaimCounter;
0343
0344 public:
0345 ExplodedGraph();
0346 ~ExplodedGraph();
0347
0348
0349
0350
0351
0352 ExplodedNode *getNode(const ProgramPoint &L, ProgramStateRef State,
0353 bool IsSink = false,
0354 bool* IsNew = nullptr);
0355
0356
0357
0358
0359
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
0370 ExplodedNode *addRoot(ExplodedNode *V) {
0371 Roots.push_back(V);
0372 return V;
0373 }
0374
0375
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
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
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434 std::unique_ptr<ExplodedGraph>
0435 trim(ArrayRef<const NodeTy *> Nodes,
0436 InterExplodedGraphMap *ForwardMap = nullptr,
0437 InterExplodedGraphMap *InverseMap = nullptr) const;
0438
0439
0440
0441 void enableNodeReclamation(unsigned Interval) {
0442 ReclaimCounter = ReclaimNodeInterval = Interval;
0443 }
0444
0445
0446
0447 void reclaimRecentlyAllocatedNodes();
0448
0449
0450
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 }
0499
0500 }
0501
0502
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 }
0540
0541 #endif