svf-lib 1.0.2681 → 1.0.2682

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
@@ -697,7 +697,7 @@ public:
697
697
  return std::to_string(_iVal);
698
698
  }
699
699
 
700
- //%}
700
+ //%}
701
701
 
702
702
  bool is_real() const
703
703
  {
@@ -197,7 +197,7 @@ public:
197
197
  return getGNode(id);
198
198
  }
199
199
 
200
- /// Whether has the CDGNode
200
+ /// Whether has the CDGNode
201
201
  inline bool hasCDGNode(NodeID id) const
202
202
  {
203
203
  return hasGNode(id);
@@ -503,6 +503,11 @@ template<> struct GenericGraphTraits<SVF::CallGraph*> : public GenericGraphTrait
503
503
  {
504
504
  typedef SVF::CallGraphNode*NodeRef;
505
505
 
506
+ static const SVF::CallGraphNode* getRawNode(const SVF::CallGraphNode* n)
507
+ {
508
+ return n;
509
+ }
510
+
506
511
  // Graph-intrinsic queries shared with the sliced-view specialisation
507
512
  // (GenericGraphTraits<const SlicedThreadCallGraphView*>).
508
513
  //@{
@@ -514,10 +519,36 @@ template<> struct GenericGraphTraits<SVF::CallGraph*> : public GenericGraphTrait
514
519
  for (SVF::CallGraphEdge* e : n->getInEdges())
515
520
  out.push_back(e);
516
521
  }
517
- /// The CallGraph object whose nodes an analysis over this graph scans.
518
- static const SVF::CallGraph* getCallGraph(const SVF::CallGraph* g)
522
+ static void getOutEdges(const SVF::CallGraph*, const SVF::CallGraphNode* n,
523
+ std::vector<const SVF::CallGraphEdge*>& out)
524
+ {
525
+ out.clear();
526
+ for (SVF::CallGraphEdge* e : n->getOutEdges())
527
+ out.push_back(e);
528
+ }
529
+ static void getDirectCalls(const SVF::CallGraph*, const SVF::CallGraphEdge* e,
530
+ std::vector<const SVF::CallICFGNode*>& out)
531
+ {
532
+ out.assign(e->getDirectCalls().begin(), e->getDirectCalls().end());
533
+ }
534
+ static void getIndirectCalls(const SVF::CallGraph*, const SVF::CallGraphEdge* e,
535
+ std::vector<const SVF::CallICFGNode*>& out)
536
+ {
537
+ out.assign(e->getIndirectCalls().begin(), e->getIndirectCalls().end());
538
+ }
539
+ static bool containsCallSite(const SVF::CallGraph*,
540
+ const SVF::CallGraphEdge* e,
541
+ const SVF::CallICFGNode* callSite)
542
+ {
543
+ return e->getDirectCalls().count(callSite) ||
544
+ e->getIndirectCalls().count(callSite);
545
+ }
546
+ static void getCallees(SVF::CallGraph* g,
547
+ const SVF::CallICFGNode* callSite,
548
+ SVF::CallGraph::FunctionSet& callees)
519
549
  {
520
- return g;
550
+ callees.clear();
551
+ g->getCallees(callSite, callees);
521
552
  }
522
553
  //@}
523
554
  };
@@ -309,6 +309,12 @@ template<> struct GenericGraphTraits<SVF::ICFG*> : public GenericGraphTraits<SVF
309
309
  {
310
310
  return fun->getEntryBlock()->front();
311
311
  }
312
+ /// Exit node of fun under the whole ICFG.
313
+ static const SVF::ICFGNode* getFunExit(SVF::ICFG* graph,
314
+ const SVF::FunObjVar* fun)
315
+ {
316
+ return graph->getFunExitICFGNode(fun);
317
+ }
312
318
  /// Nodes of fun contained in this graph (whole ICFG: all of them).
313
319
  static void getFunICFGNodes(SVF::ICFG*, const SVF::FunObjVar* fun,
314
320
  std::vector<const SVF::ICFGNode*>& out)
@@ -500,6 +500,7 @@ namespace SVF
500
500
  template<> struct GenericGraphTraits<SVF::SVFG*> : public GenericGraphTraits<SVF::GenericGraph<SVF::SVFGNode,SVF::SVFGEdge>* >
501
501
  {
502
502
  typedef SVF::SVFGNode *NodeRef;
503
+ static constexpr bool isFilteredGraph = false;
503
504
 
504
505
  /// Whether n belongs to this graph (the whole SVFG contains every node).
505
506
  /// Mirrored by GenericGraphTraits<const SlicedSVFGView*>, so a solver
@@ -508,6 +509,11 @@ template<> struct GenericGraphTraits<SVF::SVFG*> : public GenericGraphTraits<SVF
508
509
  {
509
510
  return true;
510
511
  }
512
+
513
+ static bool containsEdge(SVF::SVFG*, const SVF::SVFGEdge*)
514
+ {
515
+ return true;
516
+ }
511
517
  };
512
518
 
513
519
  } // End namespace llvm
@@ -24,10 +24,6 @@
24
24
  * SlicedGraphs.h
25
25
  *
26
26
  * Author: Jiawei Yang
27
- *
28
- * General non-owning sliced views of the ICFG, PAG, and (Thread)CallGraph, and
29
- * their GenericGraphTraits specialisations, so a slice works with SVF's generic
30
- * graph algorithms and GraphWriter.
31
27
  */
32
28
 
33
29
  #ifndef GRAPHS_SLICEDGRAPHS_H
@@ -45,13 +41,9 @@
45
41
  #include "SVFIR/SVFStatements.h"
46
42
  #include "SVFIR/SVFVariables.h"
47
43
  #include <cstddef>
48
- #include <fstream>
49
44
  #include <iterator>
50
45
  #include <memory>
51
- #include <set>
52
46
  #include <string>
53
- #include <unordered_map>
54
- #include <unordered_set>
55
47
  #include <vector>
56
48
  #include <utility>
57
49
 
@@ -66,14 +58,9 @@ namespace SVF
66
58
  class SlicedICFGView
67
59
  {
68
60
  public:
69
- /// Build complete ICFG view from keepNodes and keptFunctions
70
- // buildBridged=false skips bridged-edge construction for views whose control
71
- // flow is never walked (e.g. the FSPTA view, used only for isKeptNode).
61
+ /// Build an ICFG view from its explicit node membership.
72
62
  SlicedICFGView(ICFG* icfg,
73
- CallGraph* cg,
74
- const OrderedSet<const ICFGNode*>& keepNodes,
75
- const OrderedSet<const FunObjVar*>& keptFunctions,
76
- bool buildBridged = true);
63
+ const OrderedSet<const ICFGNode*>& keepNodes);
77
64
 
78
65
  /// Get successor nodes (including bridged edges)
79
66
  void getSuccNodes(const ICFGNode* node, std::vector<const ICFGNode*>& out) const;
@@ -84,10 +71,12 @@ public:
84
71
  /// Check if a node is in the sliced view
85
72
  bool isKeptNode(const ICFGNode* node) const;
86
73
 
87
- /// First kept node of fun's entry (the kept FunEntryICFGNode, else the first
88
- /// kept node of the entry block, else the original entry).
74
+ /// First kept node of fun's entry, or null when fun is outside the view.
89
75
  const ICFGNode* getFunEntry(const FunObjVar* fun) const;
90
76
 
77
+ /// Kept synthetic exit node of fun, or null when fun is outside the view.
78
+ const ICFGNode* getFunExit(const FunObjVar* fun) const;
79
+
91
80
  /// Kept ICFG nodes of fun.
92
81
  void getFunICFGNodes(const FunObjVar* fun, std::vector<const ICFGNode*>& out) const;
93
82
 
@@ -122,16 +111,18 @@ public:
122
111
  private:
123
112
  ICFG* icfg;
124
113
  OrderedSet<const ICFGNode*> keptNodes;
125
- OrderedSet<const ICFGEdge*> keptEdges;
126
114
  Map<const ICFGNode*, OrderedSet<const ICFGNode*>> bridgedEdges;
127
115
  // Reverse of bridgedEdges (dst -> srcs), so getPredNodes is O(preds) instead
128
116
  // of scanning every bridged edge.
129
117
  Map<const ICFGNode*, OrderedSet<const ICFGNode*>> bridgedPreds;
130
118
  Set<const ICFGNode*> keptNodesSet; // For fast lookup
131
119
 
132
- void buildICFGSets(const OrderedSet<const ICFGNode*>& keepNodes,
133
- const OrderedSet<const FunObjVar*>& keptFunctions);
120
+ void buildICFGSets(const OrderedSet<const ICFGNode*>& keepNodes);
134
121
  void buildBridgedEdges();
122
+ static void getLocalSuccessors(
123
+ const ICFGNode* node,
124
+ const Map<const ICFGNode*, const ICFGNode*>& callsiteReturnNodes,
125
+ std::vector<const ICFGNode*>& successors);
135
126
  };
136
127
 
137
128
  //===----------------------------------------------------------------------===//
@@ -187,7 +178,7 @@ class SlicedThreadCallGraphView
187
178
  public:
188
179
  SlicedThreadCallGraphView(ThreadCallGraph* tcg,
189
180
  const OrderedSet<const FunObjVar*>& keptFunctions,
190
- const OrderedSet<const ICFGNode*>& extendedKeptNodes = OrderedSet<const ICFGNode*>());
181
+ const OrderedSet<const ICFGNode*>& extendedKeptNodes);
191
182
 
192
183
  /// Get out edges of a node (only returns kept edges and target nodes)
193
184
  void getOutEdgesOf(const CallGraphNode* node, std::vector<const CallGraphEdge*>& out) const;
@@ -195,6 +186,27 @@ public:
195
186
  /// Get in edges of a node (only returns kept edges and source nodes)
196
187
  void getInEdgesOf(const CallGraphNode* node, std::vector<const CallGraphEdge*>& out) const;
197
188
 
189
+ /// Retained callsites carried by an aggregated call-graph edge.
190
+ void getDirectCallsOf(const CallGraphEdge* edge,
191
+ std::vector<const CallICFGNode*>& out) const;
192
+ void getIndirectCallsOf(const CallGraphEdge* edge,
193
+ std::vector<const CallICFGNode*>& out) const;
194
+
195
+ /// Whether this precise callsite-to-callee relation is retained.
196
+ bool containsCallSite(const CallGraphEdge* edge,
197
+ const CallICFGNode* callSite) const;
198
+
199
+ /// Retained callees of a callsite.
200
+ void getCalleesOf(const CallICFGNode* callSite,
201
+ CallGraph::FunctionSet& callees) const;
202
+
203
+ /// Retained thread relations indexed by their fork/join callsite. Join
204
+ /// relations are deliberately separate from normal CallGraph adjacency.
205
+ void getForkEdgesOf(const CallICFGNode* callSite,
206
+ std::vector<const CallGraphEdge*>& out) const;
207
+ void getJoinEdgesOf(const CallICFGNode* callSite,
208
+ std::vector<const CallGraphEdge*>& out) const;
209
+
198
210
  /// Check if a node is in the sliced view
199
211
  bool isKeptNode(const CallGraphNode* node) const;
200
212
 
@@ -209,17 +221,11 @@ public:
209
221
  return keptFunctionsSet;
210
222
  }
211
223
 
212
- /// Get all kept edges
213
- inline const CallGraph::CallGraphEdgeSet& getKeptEdges() const
214
- {
215
- return keptEdges;
216
- }
217
-
218
224
  /// Canonical edge membership: keptEdges excludes edges whose call site was
219
225
  /// pruned, so endpoint checks alone are not enough (queries/traits use this).
220
226
  inline bool isKeptEdge(const CallGraphEdge* e) const
221
227
  {
222
- return keptEdges.find(const_cast<CallGraphEdge*>(e)) != keptEdges.end();
228
+ return keptEdges.find(e) != keptEdges.end();
223
229
  }
224
230
 
225
231
  /// Indirect call sites that lost all targets after filtering
@@ -231,14 +237,9 @@ public:
231
237
  /// Dump sliced ThreadCallGraph to dot file
232
238
  void dump(const std::string& filename) const;
233
239
 
234
- /// Get original ThreadCallGraph
235
- inline ThreadCallGraph* getOriginalThreadCallGraph() const
236
- {
237
- return tcg;
238
- }
239
-
240
- /// Get original CallGraph (ThreadCallGraph inherits from CallGraph)
241
- inline CallGraph* getOriginalCallGraph() const
240
+ /// Backing graph access for the graph-traits implementation only. Analysis
241
+ /// traversal must use this view's filtered methods above.
242
+ inline CallGraph* getBackingCallGraph() const
242
243
  {
243
244
  return tcg;
244
245
  }
@@ -246,7 +247,9 @@ public:
246
247
  private:
247
248
  ThreadCallGraph* tcg;
248
249
  OrderedSet<const CallGraphNode*> keptNodes;
249
- CallGraph::CallGraphEdgeSet keptEdges;
250
+ Set<const CallGraphEdge*> keptEdges;
251
+ Map<const CallGraphEdge*, CallGraphEdge::CallInstSet> keptDirectCalls;
252
+ Map<const CallGraphEdge*, CallGraphEdge::CallInstSet> keptIndirectCalls;
250
253
  Set<const FunObjVar*> keptFunctionsSet; // For fast lookup
251
254
  Set<const CallICFGNode*> indirectSitesWithEmptyTargets;
252
255
  OrderedSet<const ICFGNode*> extendedKeptNodes; // For checking if call sites are kept
@@ -256,21 +259,16 @@ private:
256
259
  };
257
260
 
258
261
  //===----------------------------------------------------------------------===//
259
- // SlicedSVFGView - non-owning sliced view of the (thread-aware) SVFG.
260
- // Retained nodes: everything except Load/Store statement nodes whose ICFG node
261
- // was sliced out; structural nodes (Addr/Copy/Gep, MSSA phi/mu/chi, call/return
262
- // boundaries) always remain so inter-procedural and memory-SSA flow is intact.
263
- // Deliberately NO bridge edges: bridging removed SVFG nodes could fabricate
264
- // value-flow paths that do not exist in the original graph. Removed nodes act
265
- // as propagation barriers (matching the sliced FSAM solve).
262
+ // SlicedSVFGView - non-owning exact node-induced view of an SVFG.
263
+ // Membership is supplied as an explicit node-ID set; an edge is visible iff
264
+ // both endpoints are retained. There are deliberately no bridge edges, since
265
+ // bridging would fabricate value-flow paths.
266
266
  //===----------------------------------------------------------------------===//
267
267
  class SlicedSVFGView
268
268
  {
269
269
  public:
270
- /// Membership needs only the sliced ICFG view; the SVFG handle (for node
271
- /// iteration and dumping) may be bound later, once the solver has built it.
272
- explicit SlicedSVFGView(const SlicedICFGView* icfgView, const SVFG* svfg = nullptr)
273
- : icfgView(icfgView), svfg(svfg) {}
270
+ SlicedSVFGView(const SVFG* svfg, const NodeBS& retainedNodeIds)
271
+ : svfg(svfg), retainedNodeIds(retainedNodeIds) {}
274
272
 
275
273
  /// Whether the node is retained (see the class comment for the rule).
276
274
  bool isKeptNode(const SVFGNode* n) const;
@@ -281,26 +279,18 @@ public:
281
279
  return isKeptNode(e->getSrcNode()) && isKeptNode(e->getDstNode());
282
280
  }
283
281
 
284
- inline const SlicedICFGView* getICFGView() const
285
- {
286
- return icfgView;
287
- }
288
282
  inline const SVFG* getSVFG() const
289
283
  {
290
284
  return svfg;
291
285
  }
292
- /// Bind the underlying SVFG (enables node iteration and dumping).
293
- inline void setSVFG(const SVFG* g)
294
- {
295
- svfg = g;
296
- }
286
+ size_t getKeptNodeCount() const;
297
287
 
298
288
  /// Dump the sliced SVFG (retained nodes/edges only) via GraphWriter.
299
289
  void dump(const std::string& filename) const;
300
290
 
301
291
  private:
302
- const SlicedICFGView* icfgView;
303
- const SVFG* svfg;
292
+ const SVFG* svfg = nullptr;
293
+ NodeBS retainedNodeIds;
304
294
  };
305
295
 
306
296
  //===----------------------------------------------------------------------===//
@@ -310,11 +300,10 @@ private:
310
300
  class SlicedSVFIRView
311
301
  {
312
302
  public:
313
- SlicedSVFIRView(SVFIR* svfIr,
314
- CallGraph* cg,
303
+ SlicedSVFIRView(SVFIR* svfir,
304
+ ThreadCallGraph& callGraph,
315
305
  ICFG* icfg,
316
- const OrderedSet<const ICFGNode*>& keepNodes,
317
- bool buildBridged = true);
306
+ const OrderedSet<const ICFGNode*>& keepNodes);
318
307
 
319
308
  /// Get SlicedICFGView
320
309
  inline const SlicedICFGView* getICFG() const
@@ -329,10 +318,12 @@ public:
329
318
  /// Get SlicedPAGView
330
319
  inline const SlicedPAGView* getPAG() const
331
320
  {
321
+ ensurePAGView();
332
322
  return pagView.get();
333
323
  }
334
324
  inline SlicedPAGView* getPAG()
335
325
  {
326
+ ensurePAGView();
336
327
  return pagView.get();
337
328
  }
338
329
 
@@ -361,34 +352,27 @@ public:
361
352
  /// Get all kept statements
362
353
  inline const OrderedSet<const SVFStmt*>& getKeptStatements() const
363
354
  {
364
- return pagView->getKeptStmts();
355
+ return getPAG()->getKeptStmts();
365
356
  }
366
357
 
367
- /// In-edges of a call-graph node under the sliced ThreadCallGraph view (the
368
- /// full node in-edges if no TCG view was built).
369
- void getInEdgesOfCallGraphNode(const CallGraphNode* node,
370
- std::vector<const CallGraphEdge*>& out) const;
371
-
372
- /// The CallGraph the sliced analyses scan: the sliced ThreadCallGraph's
373
- /// original CallGraph, or the full PAG CallGraph if no TCG view was built.
374
- const CallGraph* getAnalysisCallGraph() const;
375
-
376
358
  /// Dump all views to files
377
359
  void dumpAll(const std::string& prefix) const;
378
360
 
379
361
  /// Get original SVFIR
380
362
  inline SVFIR* getSVFIR() const
381
363
  {
382
- return svfIr;
364
+ return svfir;
383
365
  }
384
366
 
385
367
  /// Output statistics
386
368
  void dumpStats(const std::string& prefix = "") const;
387
369
 
388
370
  private:
389
- SVFIR* svfIr;
371
+ void ensurePAGView() const;
372
+
373
+ SVFIR* svfir;
390
374
  std::unique_ptr<SlicedICFGView> icfgView;
391
- std::unique_ptr<SlicedPAGView> pagView;
375
+ mutable std::unique_ptr<SlicedPAGView> pagView;
392
376
  std::unique_ptr<SlicedThreadCallGraphView> tcgView;
393
377
  };
394
378
 
@@ -651,7 +635,7 @@ public:
651
635
 
652
636
  friend bool operator==(const SlicedICFGNodeIter& a, const SlicedICFGNodeIter& b)
653
637
  {
654
- return a.it == b.it;
638
+ return a.view == b.view && a.it == b.it;
655
639
  }
656
640
  friend bool operator!=(const SlicedICFGNodeIter& a, const SlicedICFGNodeIter& b)
657
641
  {
@@ -851,7 +835,7 @@ public:
851
835
  }
852
836
  friend bool operator==(const SlicedCGNodeIter& a, const SlicedCGNodeIter& b)
853
837
  {
854
- return a.it == b.it;
838
+ return a.view == b.view && a.it == b.it;
855
839
  }
856
840
  friend bool operator!=(const SlicedCGNodeIter& a, const SlicedCGNodeIter& b)
857
841
  {
@@ -1052,7 +1036,7 @@ public:
1052
1036
  }
1053
1037
  friend bool operator==(const SlicedPAGNodeIter& a, const SlicedPAGNodeIter& b)
1054
1038
  {
1055
- return a.it == b.it;
1039
+ return a.view == b.view && a.it == b.it;
1056
1040
  }
1057
1041
  friend bool operator!=(const SlicedPAGNodeIter& a, const SlicedPAGNodeIter& b)
1058
1042
  {
@@ -1066,7 +1050,7 @@ private:
1066
1050
 
1067
1051
  //===----------------------------------------------------------------------===//
1068
1052
  // SlicedSVFGView traits support (no bridged edges; membership is the view's
1069
- // retained-node rule, so removed nodes are propagation barriers).
1053
+ // retained-node rule, so removed nodes never enter SCC/worklist traversal).
1070
1054
  //===----------------------------------------------------------------------===//
1071
1055
 
1072
1056
  using SlicedSVFGNodeRef = SlicedNodeRef<SlicedSVFGView, SVFGNode>;
@@ -1258,7 +1242,7 @@ public:
1258
1242
  }
1259
1243
  friend bool operator==(const SlicedSVFGNodeIter& a, const SlicedSVFGNodeIter& b)
1260
1244
  {
1261
- return a.it == b.it;
1245
+ return a.view == b.view && a.it == b.it;
1262
1246
  }
1263
1247
  friend bool operator!=(const SlicedSVFGNodeIter& a, const SlicedSVFGNodeIter& b)
1264
1248
  {
@@ -1307,6 +1291,10 @@ struct GenericGraphTraits<const SlicedICFGView*>
1307
1291
  {
1308
1292
  return g->getFunEntry(fun);
1309
1293
  }
1294
+ static const ICFGNode* getFunExit(const SlicedICFGView* g, const FunObjVar* fun)
1295
+ {
1296
+ return g->getFunExit(fun);
1297
+ }
1310
1298
  static void getFunICFGNodes(const SlicedICFGView* g, const FunObjVar* fun,
1311
1299
  std::vector<const ICFGNode*>& out)
1312
1300
  {
@@ -1453,9 +1441,46 @@ struct GenericGraphTraits<const SlicedThreadCallGraphView*>
1453
1441
  {
1454
1442
  g->getInEdgesOf(n, out);
1455
1443
  }
1456
- static const CallGraph* getCallGraph(const SlicedThreadCallGraphView* g)
1444
+ static void getOutEdges(const SlicedThreadCallGraphView* g, const CallGraphNode* n,
1445
+ std::vector<const CallGraphEdge*>& out)
1446
+ {
1447
+ g->getOutEdgesOf(n, out);
1448
+ }
1449
+ static void getDirectCalls(const SlicedThreadCallGraphView* g,
1450
+ const CallGraphEdge* e,
1451
+ std::vector<const CallICFGNode*>& out)
1452
+ {
1453
+ g->getDirectCallsOf(e, out);
1454
+ }
1455
+ static void getIndirectCalls(const SlicedThreadCallGraphView* g,
1456
+ const CallGraphEdge* e,
1457
+ std::vector<const CallICFGNode*>& out)
1458
+ {
1459
+ g->getIndirectCallsOf(e, out);
1460
+ }
1461
+ static bool containsCallSite(const SlicedThreadCallGraphView* g,
1462
+ const CallGraphEdge* e,
1463
+ const CallICFGNode* callSite)
1464
+ {
1465
+ return g->containsCallSite(e, callSite);
1466
+ }
1467
+ static void getCallees(const SlicedThreadCallGraphView* g,
1468
+ const CallICFGNode* callSite,
1469
+ CallGraph::FunctionSet& callees)
1457
1470
  {
1458
- return g->getOriginalCallGraph();
1471
+ g->getCalleesOf(callSite, callees);
1472
+ }
1473
+ static void getForkEdges(const SlicedThreadCallGraphView* g,
1474
+ const CallICFGNode* callSite,
1475
+ std::vector<const CallGraphEdge*>& out)
1476
+ {
1477
+ g->getForkEdgesOf(callSite, out);
1478
+ }
1479
+ static void getJoinEdges(const SlicedThreadCallGraphView* g,
1480
+ const CallICFGNode* callSite,
1481
+ std::vector<const CallGraphEdge*>& out)
1482
+ {
1483
+ g->getJoinEdgesOf(callSite, out);
1459
1484
  }
1460
1485
  //@}
1461
1486
 
@@ -1514,7 +1539,7 @@ struct GenericGraphTraits<const SlicedThreadCallGraphView*>
1514
1539
  }
1515
1540
  static NodeRef getNode(const SlicedThreadCallGraphView* v, NodeID id)
1516
1541
  {
1517
- const CallGraphNode* raw = v->getOriginalCallGraph()->getGNode(id);
1542
+ const CallGraphNode* raw = v->getBackingCallGraph()->getGNode(id);
1518
1543
  return NodeRef{v, (raw != nullptr && v->isKeptNode(raw)) ? raw : nullptr};
1519
1544
  }
1520
1545
  };
@@ -1685,6 +1710,7 @@ struct GenericGraphTraits<const SlicedSVFGView*>
1685
1710
  using nodes_iterator = SlicedSVFGNodeIter;
1686
1711
  using ChildIteratorType = SlicedSVFGChildIterImpl<true>;
1687
1712
  using ChildEdgeIteratorType = SlicedSVFGEdgeIterImpl<true>;
1713
+ static constexpr bool isFilteredGraph = true;
1688
1714
 
1689
1715
  static const SVFGNode* getRawNode(NodeRef n)
1690
1716
  {
@@ -1697,6 +1723,11 @@ struct GenericGraphTraits<const SlicedSVFGView*>
1697
1723
  return g->isKeptNode(n);
1698
1724
  }
1699
1725
 
1726
+ static bool containsEdge(const SlicedSVFGView* g, const SVFGEdge* e)
1727
+ {
1728
+ return g->isKeptEdge(e);
1729
+ }
1730
+
1700
1731
  static NodeRef getEntryNode(const SlicedSVFGView*)
1701
1732
  {
1702
1733
  return NodeRef{};
@@ -1747,6 +1778,10 @@ struct GenericGraphTraits<const SlicedSVFGView*>
1747
1778
  {
1748
1779
  return n.raw->getId();
1749
1780
  }
1781
+ static unsigned graphSize(const SlicedSVFGView* v)
1782
+ {
1783
+ return static_cast<unsigned>(v->getKeptNodeCount());
1784
+ }
1750
1785
  static NodeRef getNode(const SlicedSVFGView* v, NodeID id)
1751
1786
  {
1752
1787
  const SVFGNode* raw =
@@ -405,4 +405,41 @@ private:
405
405
 
406
406
  } // End namespace SVF
407
407
 
408
+ namespace SVF
409
+ {
410
+
411
+ /// Thread-specific relations are indexed by callsite rather than represented
412
+ /// uniformly in CallGraph node adjacency. In particular, ThreadJoinEdge is not
413
+ /// added to adjacency because it would introduce artificial SCC cycles.
414
+ template<>
415
+ struct GenericGraphTraits<SVF::ThreadCallGraph*>
416
+ : public GenericGraphTraits<SVF::CallGraph*>
417
+ {
418
+ static void getForkEdges(const SVF::ThreadCallGraph* graph,
419
+ const SVF::CallICFGNode* callSite,
420
+ std::vector<const SVF::CallGraphEdge*>& out)
421
+ {
422
+ out.clear();
423
+ if (!graph->hasThreadForkEdge(callSite))
424
+ return;
425
+ for (auto it = graph->getForkEdgeBegin(callSite),
426
+ end = graph->getForkEdgeEnd(callSite); it != end; ++it)
427
+ out.push_back(*it);
428
+ }
429
+
430
+ static void getJoinEdges(const SVF::ThreadCallGraph* graph,
431
+ const SVF::CallICFGNode* callSite,
432
+ std::vector<const SVF::CallGraphEdge*>& out)
433
+ {
434
+ out.clear();
435
+ if (!graph->hasThreadJoinEdge(callSite))
436
+ return;
437
+ for (auto it = graph->getJoinEdgeBegin(callSite),
438
+ end = graph->getJoinEdgeEnd(callSite); it != end; ++it)
439
+ out.push_back(*it);
440
+ }
441
+ };
442
+
443
+ } // End namespace SVF
444
+
408
445
  #endif /* RCG_H_ */
@@ -511,7 +511,7 @@ protected:
511
511
  return true;
512
512
  }
513
513
 
514
- /// Create edges between VFG nodes within a function
514
+ /// Create edges between VFG nodes within a function
515
515
  void connectDirectVFGEdges();
516
516
 
517
517
  /// Create edges between VFG nodes across functions