svf-lib 1.0.2680 → 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.
Files changed (26) hide show
  1. package/SVF-linux-aarch64/bin/mta +0 -0
  2. package/SVF-linux-aarch64/include/AE/Core/NumericValue.h +1 -1
  3. package/SVF-linux-aarch64/include/Graphs/CDG.h +1 -1
  4. package/SVF-linux-aarch64/include/Graphs/CallGraph.h +34 -3
  5. package/SVF-linux-aarch64/include/Graphs/ICFG.h +6 -0
  6. package/SVF-linux-aarch64/include/Graphs/SVFG.h +6 -0
  7. package/SVF-linux-aarch64/include/Graphs/SlicedGraphs.h +119 -84
  8. package/SVF-linux-aarch64/include/Graphs/ThreadCallGraph.h +37 -0
  9. package/SVF-linux-aarch64/include/Graphs/VFG.h +1 -1
  10. package/SVF-linux-aarch64/include/MTA/FSMPTA.h +50 -34
  11. package/SVF-linux-aarch64/include/MTA/LockAnalysis.h +95 -55
  12. package/SVF-linux-aarch64/include/MTA/MHP.h +65 -24
  13. package/SVF-linux-aarch64/include/MTA/MTA.h +99 -51
  14. package/SVF-linux-aarch64/include/MTA/MTASVFGBuilder.h +115 -50
  15. package/SVF-linux-aarch64/include/MTA/MTASlicer.h +73 -79
  16. package/SVF-linux-aarch64/include/MTA/MTAStat.h +54 -6
  17. package/SVF-linux-aarch64/include/MTA/TCT.h +13 -22
  18. package/SVF-linux-aarch64/include/SVF-LLVM/GEPTypeBridgeIterator.h +2 -2
  19. package/SVF-linux-aarch64/include/SVF-LLVM/ObjTypeInference.h +1 -1
  20. package/SVF-linux-aarch64/include/Util/Options.h +2 -4
  21. package/SVF-linux-aarch64/include/Util/SparseBitVector.h +2 -2
  22. package/SVF-linux-aarch64/lib/libSvfCore.so.3.4 +0 -0
  23. package/SVF-linux-aarch64/lib/libSvfLLVM.so.3.4 +0 -0
  24. package/SVF-linux-x86_64/include/SVF-LLVM/GEPTypeBridgeIterator.h +7 -3
  25. package/SVF-linux-x86_64/lib/libSvfLLVM.so.3.4 +0 -0
  26. package/package.json +1 -1
@@ -36,56 +36,72 @@
36
36
  #define INCLUDE_MTA_FSMPTA_H_
37
37
 
38
38
  #include "WPA/FlowSensitive.h"
39
- #include "MTA/MHP.h"
40
- #include "MTA/LockAnalysis.h"
41
- #include "MTA/MTASVFGBuilder.h"
42
- #include "MTA/MTASlicer.h"
43
- #include <unordered_set>
39
+ #include "Graphs/SlicedGraphs.h"
40
+
41
+ #include <deque>
44
42
 
45
43
  namespace SVF
46
44
  {
47
45
 
48
- /// One solver for the whole and the sliced SVFG: SVFGGraph is SVFG* (whole;
49
- /// every node processed) or const SlicedSVFGView* (sliced; nodes outside the
50
- /// view are propagation barriers). Restriction is answered by
51
- /// GenericGraphTraits<SVFGGraph>::containsNode, resolved at compile time; the
52
- /// stock FlowSensitive transfer semantics are untouched.
46
+ class AndersenBase;
47
+ class AndersenWaveDiff;
48
+
49
+ /// Flow-sensitive solver over an already-built thread-aware SVFG. SVFGGraph is
50
+ /// either SVFG* for the whole graph or const SlicedSVFGView* for an exact slice.
51
+ /// The backing SVFG is owned by MTASVFGBuilder; this class owns only the
52
+ /// analysis state and the SCC detector for its solve graph.
53
53
  template<class SVFGGraph>
54
- class FSMPTA : public FlowSensitive
54
+ class FSMPTA final : public FlowSensitive
55
55
  {
56
56
  public:
57
- /// Constructor.
58
- /// - graph: gates the per-node transfer (the solver runs over the whole
59
- /// thread-aware SVFG). For SVFGGraph == SVFG* it may be null (every node
60
- /// is processed). A SlicedSVFGView needs only its ICFG view for membership,
61
- /// so it can be created before the SVFG itself is built here.
62
- FSMPTA(MHP* m, LockAnalysis* la, SVFGGraph graph)
63
- : FlowSensitive(m->getTCT()->getPTA()->getPAG()),
64
- mhp(m), mtaSVFGBuilder(m, la), graph(graph)
65
- {
66
- }
67
-
57
+ FSMPTA(AndersenWaveDiff& preAnalysis, SVFG& backingGraph,
58
+ SVFGGraph solveGraph);
68
59
  ~FSMPTA() override = default;
69
60
 
70
- /// Initialise: build the thread-aware SVFG, then solve sparsely on it.
71
61
  void initialize() override;
62
+ void finalize() override;
72
63
 
73
- /// Restrict the solve to the graph's nodes (whole: no restriction).
74
- void processNode(NodeID nodeId) override;
64
+ static bool supportsCurrentConfiguration();
75
65
 
76
- inline MHP* getMHP() const
77
- {
78
- return mhp;
79
- }
66
+ /// Close a backward value-flow slice over FlowSensitive's execution
67
+ /// dependencies. Besides explicit SVFG predecessors, this follows the
68
+ /// definition of every top-level pointer read through the solver-global
69
+ /// points-to map, closes future indirect-call boundary edges, and retains
70
+ /// variant-GEP transfers whose field-sensitivity side effect is global.
71
+ static NodeBS buildExecutionDependencyClosure(
72
+ SVFG* graph, AndersenBase* preAnalysis, NodeBS dependencyNodes);
73
+
74
+ protected:
75
+ NodeStack& SCCDetect() override;
76
+ void processNode(NodeID nodeId) override;
77
+ void updateConnectedNodes(const SVFGEdgeSetTy& edges) override;
80
78
 
81
79
  private:
82
- MHP* mhp;
83
- /// Owns the thread-aware SVFG used by the FS solver (must outlive `svfg`).
84
- MTASVFGBuilder mtaSVFGBuilder;
85
- /// The graph the solve is restricted to (see the constructor).
86
- SVFGGraph graph;
80
+ using SolveGraphTraits = GenericGraphTraits<SVFGGraph>;
81
+
82
+ static void enqueueSVFGNode(const SVFGNode* node, NodeBS& retained,
83
+ std::deque<NodeID>& worklist);
84
+ static void demandTopLevelPointer(const SVFVar* var, SVFG* graph,
85
+ NodeBS& demandedVars, NodeBS& retained,
86
+ std::deque<NodeID>& worklist);
87
+ static void collectNodeInputDependencies(
88
+ const SVFGNode* node, SVFG* graph, NodeBS& demandedVars,
89
+ NodeBS& retained, std::deque<NodeID>& worklist);
90
+ void buildRetainedAdjacency();
91
+ void cacheRetainedEdge(SVFGEdge* edge);
92
+
93
+ AndersenWaveDiff* preAnalysis;
94
+ SVFG* backingGraph;
95
+ SVFGGraph solveGraph;
96
+ std::unique_ptr<SCCDetection<SVFGGraph>> solveSCC;
97
+ NodeStack solveNodeStack;
98
+ Map<NodeID, std::vector<SVFGEdge*>> retainedOutEdges;
99
+ Set<const SVFGEdge*> retainedEdgeSet;
87
100
  };
88
101
 
102
+ extern template class FSMPTA<SVFG*>;
103
+ extern template class FSMPTA<const SlicedSVFGView*>;
104
+
89
105
  } // End namespace SVF
90
106
 
91
107
  #endif /* INCLUDE_MTA_FSMPTA_H_ */
@@ -25,11 +25,6 @@
25
25
  *
26
26
  * Created on: 26 Aug 2015
27
27
  * Author: pengd
28
- *
29
- * Lock analysis. One implementation runs on the whole program or a slice:
30
- * analyze() is templated on the graph handle (SVFIR* or const SlicedSVFIRView*),
31
- * as used by "Multi-Stage On-Demand Program Slicing for Modular Analysis of
32
- * Multi-Threaded Programs" (ISSTA 2026).
33
28
  */
34
29
 
35
30
  #ifndef INCLUDE_MTA_LockAnalysis_H_
@@ -79,6 +74,9 @@ public:
79
74
  typedef Set<CxtStmt> LockSpan;
80
75
  typedef Set<CxtStmt> CxtStmtSet;
81
76
  typedef Set<CxtLock> CxtLockSet;
77
+ typedef Set<CallStrCxt> CallStrCxtSet;
78
+ typedef Map<CallStrCxt, CallStrCxtSet> ContextSuffixToContexts;
79
+ typedef Map<const ICFGNode*, ContextSuffixToContexts> InstToContextSuffixMap;
82
80
 
83
81
  typedef Map<CxtLock, LockSpan> CxtLockToSpan;
84
82
  typedef Map<CxtLock, NodeBS> CxtLockToLockSet;
@@ -97,27 +95,31 @@ public:
97
95
  /// context-sensitive forward traversal from each lock site. Generate following results
98
96
  /// (1) context-sensitive lock site,
99
97
  /// (2) maps a context-sensitive lock site to its corresponding lock span.
100
- /// One implementation for the whole program and a slice: GraphT is SVFIR*
101
- /// (whole) or const SlicedSVFIRView* (sliced). Per-graph queries resolve at
102
- /// compile time via the graph* overloads in Graphs/SlicedGraphs.h.
98
+ /// The same implementation runs over full and sliced ICFG/CallGraph traits.
103
99
  template<class ICFGGraph, class CGGraph> void analyze(ICFGGraph icfg, CGGraph cg);
104
- template<class ICFGGraph, class CGGraph> void analyzeIntraProcedualLock(ICFGGraph icfg, CGGraph cg);
105
- template<class ICFGGraph, class CGGraph> bool intraForwardTraverse(ICFGGraph icfg, CGGraph cg, const ICFGNode* lock, InstSet& unlockset, InstSet& forwardInsts);
106
- template<class ICFGGraph, class CGGraph> bool intraBackwardTraverse(ICFGGraph icfg, CGGraph cg, const InstSet& unlockset, InstSet& backwardInsts);
100
+ template<class ICFGGraph>
101
+ void analyzeIntraProceduralLock(ICFGGraph icfg);
102
+ template<class ICFGGraph>
103
+ bool intraForwardTraverse(ICFGGraph icfg, const ICFGNode* lock,
104
+ InstSet& unlockSet, InstSet& forwardInsts);
105
+ template<class ICFGGraph>
106
+ bool intraBackwardTraverse(ICFGGraph icfg, const InstSet& unlockSet,
107
+ InstSet& backwardInsts);
107
108
 
108
109
  template<class ICFGGraph, class CGGraph> void collectCxtLock(ICFGGraph icfg, CGGraph cg);
109
110
  template<class ICFGGraph, class CGGraph> void analyzeLockSpanCxtStmt(ICFGGraph icfg, CGGraph cg);
110
111
 
111
- template<class ICFGGraph, class CGGraph> void collectLockUnlocksites(ICFGGraph icfg, CGGraph cg);
112
- void buildCandidateFuncSetforLock();
112
+ template<class ICFGGraph, class CGGraph> void collectLockUnlockSites(ICFGGraph icfg, CGGraph cg);
113
+ template<class CGGraph>
114
+ void buildCandidateFuncSetForLock(CGGraph cg);
113
115
 
114
116
  /// Intraprocedural locks
115
117
  //@{
116
118
  /// Return true if the lock is an intra-procedural lock
117
119
  inline bool isIntraLock(const ICFGNode* lock) const
118
120
  {
119
- assert(locksites.find(lock)!=locksites.end() && "not a lock site?");
120
- return ciLocktoSpan.find(lock)!=ciLocktoSpan.end();
121
+ assert(lockSites.find(lock)!=lockSites.end() && "not a lock site?");
122
+ return ciLockToSpan.find(lock)!=ciLockToSpan.end();
121
123
  }
122
124
 
123
125
  /// Add intra-procedural lock
@@ -126,7 +128,7 @@ public:
126
128
  for(InstSet::const_iterator it = stmts.begin(), eit = stmts.end(); it!=eit; ++it)
127
129
  {
128
130
  instCILocksMap[*it].insert(lockSite);
129
- ciLocktoSpan[lockSite].insert(*it);
131
+ ciLockToSpan[lockSite].insert(*it);
130
132
  }
131
133
  }
132
134
 
@@ -135,7 +137,7 @@ public:
135
137
  {
136
138
  for(InstSet::const_iterator it = stmts.begin(), eit = stmts.end(); it!=eit; ++it)
137
139
  {
138
- instTocondCILocksMap[*it].insert(lockSite);
140
+ instToCondCILocksMap[*it].insert(lockSite);
139
141
  }
140
142
  }
141
143
 
@@ -148,7 +150,7 @@ public:
148
150
  /// Return true if a statement is inside a partial lock/unlock pair (conditional lock with unconditional unlock)
149
151
  inline bool isInsideCondIntraLock(const ICFGNode* stmt) const
150
152
  {
151
- return instTocondCILocksMap.find(stmt)!=instTocondCILocksMap.end();
153
+ return instToCondCILocksMap.find(stmt)!=instToCondCILocksMap.end();
152
154
  }
153
155
 
154
156
  /// Whether a statement has an (unconditional) intra-procedural lock set, i.e.
@@ -165,6 +167,16 @@ public:
165
167
  assert(it!=instCILocksMap.end() && "intralock not found!");
166
168
  return it->second;
167
169
  }
170
+
171
+ /// Return the conditional intra-procedural locks whose may-spans contain
172
+ /// stmt. Slicing needs these witnesses even though a conditional lock is
173
+ /// not strong enough to prove mutual exclusion at the client query.
174
+ inline const InstSet& getCondIntraLockSet(const ICFGNode* stmt) const
175
+ {
176
+ InstToInstSetMap::const_iterator it = instToCondCILocksMap.find(stmt);
177
+ assert(it!=instToCondCILocksMap.end() && "conditional intralock not found!");
178
+ return it->second;
179
+ }
168
180
  //@}
169
181
 
170
182
  /// Context-sensitive locks
@@ -173,14 +185,14 @@ public:
173
185
  inline void addCxtLock(const CallStrCxt& cxt,const ICFGNode* inst)
174
186
  {
175
187
  CxtLock cxtlock(cxt,inst);
176
- cxtLockset.insert(cxtlock);
188
+ cxtLockSet.insert(cxtlock);
177
189
  DBOUT(DMTA, SVFUtil::outs() << "LockAnalysis Process new lock "; cxtlock.dump());
178
190
  }
179
191
 
180
192
  /// Get context-sensitive lock
181
193
  inline bool hasCxtLock(const CxtLock& cxtLock) const
182
194
  {
183
- return cxtLockset.find(cxtLock)!=cxtLockset.end();
195
+ return cxtLockSet.find(cxtLock)!=cxtLockSet.end();
184
196
  }
185
197
 
186
198
  /// Return true if the intersection of two locksets is not empty
@@ -216,7 +228,7 @@ public:
216
228
  /// Return true if it is a candidate function
217
229
  inline bool isLockCandidateFun(const FunObjVar* fun) const
218
230
  {
219
- return lockcandidateFuncSet.find(fun)!=lockcandidateFuncSet.end();
231
+ return lockCandidateFuncSet.find(fun)!=lockCandidateFuncSet.end();
220
232
  }
221
233
 
222
234
  /// Context-sensitive statement and lock spans
@@ -233,18 +245,39 @@ public:
233
245
  assert(it != instToCxtStmtSet.end());
234
246
  return it->second;
235
247
  }
236
- inline bool hasCxtLockfromCxtStmt(const CxtStmt& cts) const
248
+ /// Index a callsite context by each of its suffixes (including itself and
249
+ /// the empty suffix). handleRet can then retrieve exactly the contexts
250
+ /// accepted by TCT::isContextSuffix without scanning every callsite state.
251
+ inline void indexCallsiteContext(const ICFGNode* inst, const CallStrCxt& cxt)
252
+ {
253
+ ContextSuffixToContexts& suffixIndex = callsiteContextSuffixIndex[inst];
254
+ for (size_t begin = 0; begin <= cxt.size(); ++begin)
255
+ {
256
+ CallStrCxt suffix(cxt.begin() + begin, cxt.end());
257
+ suffixIndex[suffix].insert(cxt);
258
+ }
259
+ }
260
+ inline const CallStrCxtSet* getCallsiteContextsWithSuffix(
261
+ const ICFGNode* inst, const CallStrCxt& suffix) const
262
+ {
263
+ InstToContextSuffixMap::const_iterator instIt = callsiteContextSuffixIndex.find(inst);
264
+ if (instIt == callsiteContextSuffixIndex.end())
265
+ return nullptr;
266
+ ContextSuffixToContexts::const_iterator suffixIt = instIt->second.find(suffix);
267
+ return suffixIt == instIt->second.end() ? nullptr : &suffixIt->second;
268
+ }
269
+ inline bool hasCxtLockFromCxtStmt(const CxtStmt& cts) const
237
270
  {
238
271
  CxtStmtToCxtLockSet::const_iterator it = cxtStmtToCxtLockSet.find(cts);
239
272
  return (it != cxtStmtToCxtLockSet.end());
240
273
  }
241
- inline const CxtLockSet& getCxtLockfromCxtStmt(const CxtStmt& cts) const
274
+ inline const CxtLockSet& getCxtLockFromCxtStmt(const CxtStmt& cts) const
242
275
  {
243
276
  CxtStmtToCxtLockSet::const_iterator it = cxtStmtToCxtLockSet.find(cts);
244
277
  assert(it != cxtStmtToCxtLockSet.end());
245
278
  return it->second;
246
279
  }
247
- inline CxtLockSet& getCxtLockfromCxtStmt(const CxtStmt& cts)
280
+ inline CxtLockSet& getCxtLockFromCxtStmt(const CxtStmt& cts)
248
281
  {
249
282
  CxtStmtToCxtLockSet::iterator it = cxtStmtToCxtLockSet.find(cts);
250
283
  assert(it != cxtStmtToCxtLockSet.end());
@@ -253,7 +286,7 @@ public:
253
286
  /// Add context-sensitive statement
254
287
  inline bool addCxtStmtToSpan(const CxtStmt& cts, const CxtLock& cl)
255
288
  {
256
- cxtLocktoSpan[cl].insert(cts);
289
+ cxtLockToSpan[cl].insert(cts);
257
290
  return cxtStmtToCxtLockSet[cts].insert(cl).second;
258
291
  }
259
292
  /// Add context-sensitive statement
@@ -263,28 +296,24 @@ public:
263
296
  if(find)
264
297
  {
265
298
  cxtStmtToCxtLockSet[cts].erase(cl);
266
- cxtLocktoSpan[cl].erase(cts);
299
+ cxtLockToSpan[cl].erase(cts);
267
300
  }
268
301
  return find;
269
302
  }
270
303
 
271
- CxtStmtToCxtLockSet getCSTCLS()
272
- {
273
- return cxtStmtToCxtLockSet;
274
- }
275
304
  /// Touch this context statement
276
305
  inline void touchCxtStmt(CxtStmt& cts)
277
306
  {
278
307
  cxtStmtToCxtLockSet[cts];
279
308
  }
280
- inline bool hasSpanfromCxtLock(const CxtLock& cl)
309
+ inline bool hasSpanFromCxtLock(const CxtLock& cl)
281
310
  {
282
- return cxtLocktoSpan.find(cl) != cxtLocktoSpan.end();
311
+ return cxtLockToSpan.find(cl) != cxtLockToSpan.end();
283
312
  }
284
- inline LockSpan& getSpanfromCxtLock(const CxtLock& cl)
313
+ inline LockSpan& getSpanFromCxtLock(const CxtLock& cl)
285
314
  {
286
- assert(cxtLocktoSpan.find(cl) != cxtLocktoSpan.end());
287
- return cxtLocktoSpan[cl];
315
+ assert(cxtLockToSpan.find(cl) != cxtLockToSpan.end());
316
+ return cxtLockToSpan[cl];
288
317
  }
289
318
  //@}
290
319
 
@@ -334,7 +363,7 @@ public:
334
363
 
335
364
  inline u32_t getNumOfCxtLocks()
336
365
  {
337
- return cxtLockset.size();
366
+ return cxtLockSet.size();
338
367
  }
339
368
  /// Print locks and spans
340
369
  void printLocks(const CxtStmt& cts);
@@ -354,6 +383,11 @@ protected:
354
383
  /// Handle return
355
384
  template<class ICFGGraph, class CGGraph> void handleRet(ICFGGraph icfg, CGGraph cg, const CxtStmt& cts);
356
385
 
386
+ /// Propagate a callee-exit lock state to one matching callsite context.
387
+ void handleReturnAtCallsite(const CxtStmt& exitCxtStmt,
388
+ const FunObjVar* callee, const ICFGNode* callsite,
389
+ const std::vector<const ICFGNode*>& successors);
390
+
357
391
  /// Handle intra
358
392
  template<class ICFGGraph, class CGGraph> void handleIntra(ICFGGraph icfg, CGGraph cg, const CxtStmt& cts);
359
393
 
@@ -372,8 +406,8 @@ protected:
372
406
  /// Transfer function for marking context-sensitive statement
373
407
  void markCxtStmtFlag(const CxtStmt& tgr, const CxtStmt& src)
374
408
  {
375
- const CxtLockSet& srclockset = getCxtLockfromCxtStmt(src);
376
- if(hasCxtLockfromCxtStmt(tgr)== false)
409
+ const CxtLockSet& srclockset = getCxtLockFromCxtStmt(src);
410
+ if(hasCxtLockFromCxtStmt(tgr)== false)
377
411
  {
378
412
  for(CxtLockSet::const_iterator it = srclockset.begin(), eit = srclockset.end(); it!=eit; ++it)
379
413
  {
@@ -383,23 +417,26 @@ protected:
383
417
  }
384
418
  else
385
419
  {
386
- if(intersect(getCxtLockfromCxtStmt(tgr),srclockset))
420
+ if(intersect(getCxtLockFromCxtStmt(tgr),srclockset))
421
+ {
387
422
  pushToCTSWorkList(tgr);
423
+ }
388
424
  }
389
425
  }
390
426
  bool intersect(CxtLockSet& tgrlockset, const CxtLockSet& srclockset)
391
427
  {
392
- CxtLockSet toBeDeleted;
393
- for(CxtLockSet::const_iterator it = tgrlockset.begin(), eit = tgrlockset.end(); it!=eit; ++it)
428
+ bool changed = false;
429
+ for (CxtLockSet::iterator it = tgrlockset.begin(); it != tgrlockset.end(); )
394
430
  {
395
- if(srclockset.find(*it)==srclockset.end())
396
- toBeDeleted.insert(*it);
397
- }
398
- for(CxtLockSet::const_iterator it = toBeDeleted.begin(), eit = toBeDeleted.end(); it!=eit; ++it)
399
- {
400
- tgrlockset.erase(*it);
431
+ if (srclockset.find(*it) == srclockset.end())
432
+ {
433
+ it = tgrlockset.erase(it);
434
+ changed = true;
435
+ }
436
+ else
437
+ ++it;
401
438
  }
402
- return !toBeDeleted.empty();
439
+ return changed;
403
440
  }
404
441
 
405
442
  /// Clear flags
@@ -505,13 +542,16 @@ protected:
505
542
  /// Map a statement to all its context-sensitive statements
506
543
  InstToCxtStmtSet instToCxtStmtSet;
507
544
 
545
+ /// Incremental exact suffix index for contexts observed at callsites.
546
+ InstToContextSuffixMap callsiteContextSuffixIndex;
547
+
508
548
  /// Context-sensitive locks
509
- CxtLockSet cxtLockset;
549
+ CxtLockSet cxtLockSet;
510
550
 
511
551
  /// Map a context-sensitive lock to its lock span statements
512
552
  /// Map a context-sensitive statement to its context-sensitive lock
513
553
  //@{
514
- CxtLockToSpan cxtLocktoSpan;
554
+ CxtLockToSpan cxtLockToSpan;
515
555
  CxtStmtToCxtLockSet cxtStmtToCxtLockSet;
516
556
  //@}
517
557
 
@@ -523,20 +563,20 @@ protected:
523
563
 
524
564
  /// Collecting lock/unlock sites
525
565
  //@{
526
- InstSet locksites;
527
- InstSet unlocksites;
566
+ InstSet lockSites;
567
+ InstSet unlockSites;
528
568
  //@}
529
569
 
530
570
  /// Candidate functions which relevant to locks/unlocks
531
571
  //@{
532
- FunSet lockcandidateFuncSet;
572
+ FunSet lockCandidateFuncSet;
533
573
  //@}
534
574
 
535
575
  /// Used for context-insensitive intra-procedural locks
536
576
  //@{
537
- CILockToSpan ciLocktoSpan;
577
+ CILockToSpan ciLockToSpan;
538
578
  InstToInstSetMap instCILocksMap;
539
- InstToInstSetMap instTocondCILocksMap;
579
+ InstToInstSetMap instToCondCILocksMap;
540
580
  //@}
541
581
 
542
582
  public:
@@ -25,11 +25,6 @@
25
25
  *
26
26
  * Created on: Jan 21, 2014
27
27
  * Author: Yulei Sui, Peng Di
28
- *
29
- * May-happen-in-parallel analysis. One implementation runs on the whole program
30
- * or a slice: analyze() is templated on the ICFG and CallGraph it traverses
31
- * (whole graphs or their sliced views), as used by "Multi-Stage On-Demand Program Slicing for
32
- * Modular Analysis of Multi-Threaded Programs" (ISSTA 2026).
33
28
  */
34
29
 
35
30
  #ifndef MHP_H_
@@ -62,6 +57,17 @@ public:
62
57
  typedef Set<CxtThreadStmt> CxtThreadStmtSet;
63
58
  typedef Map<CxtThreadStmt,NodeBS> ThreadStmtToThreadInterleav;
64
59
  typedef Map<const ICFGNode*,CxtThreadStmtSet> InstToThreadStmtSetMap;
60
+ /// Query-only exact compression of the context-sensitive fixed point.
61
+ /// For one ICFG node, interleavingByTid[t] is the union of the
62
+ /// interleaving sets of every calling context in which thread t reaches
63
+ /// the node. MHP's existential context-pair query factors exactly through
64
+ /// these per-tid unions (see mayHappenInParallelInst).
65
+ struct NodeThreadSummary
66
+ {
67
+ NodeBS tids;
68
+ Map<NodeID, NodeBS> interleavingByTid;
69
+ };
70
+ typedef Map<const ICFGNode*, NodeThreadSummary> InstToThreadSummaryMap;
65
71
  typedef SVFLoopAndDomInfo::LoopBBs LoopBBs;
66
72
 
67
73
  typedef Set<CxtStmt> LockSpan;
@@ -69,8 +75,17 @@ public:
69
75
  typedef std::pair<const FunObjVar*,const FunObjVar*> FuncPair;
70
76
  typedef Map<FuncPair, bool> FuncPairToBool;
71
77
 
72
- /// Constructor
73
- MHP(TCT* t);
78
+ enum class StateRepresentation
79
+ {
80
+ MaterializedContexts,
81
+ QuerySummaries
82
+ };
83
+
84
+ /// Construct MHP and initialize its graph-dependent ForkJoinAnalysis.
85
+ template<class ICFGGraph, class CGGraph>
86
+ static std::unique_ptr<MHP> create(
87
+ TCT* t, ICFGGraph icfg, CGGraph cg,
88
+ StateRepresentation representation = StateRepresentation::MaterializedContexts);
74
89
 
75
90
  /// Destructor
76
91
  virtual ~MHP();
@@ -100,13 +115,16 @@ public:
100
115
  /// Whether the function is connected from main function in thread call graph
101
116
  bool isConnectedfromMain(const FunObjVar* fun);
102
117
 
103
- // LockSpan getSpanfromCxtLock(NodeID l);
104
118
  /// Interface to query whether two instructions may happen-in-parallel
105
119
  virtual bool mayHappenInParallel(const ICFGNode* i1, const ICFGNode* i2);
106
120
  virtual bool mayHappenInParallelCache(const ICFGNode* i1, const ICFGNode* i2);
107
121
  virtual bool mayHappenInParallelInst(const ICFGNode* i1, const ICFGNode* i2);
108
122
  virtual bool executedByTheSameThread(const ICFGNode* i1, const ICFGNode* i2);
109
123
 
124
+ /// Representation-independent per-thread summary used by MHP clients.
125
+ /// Available after analyze() in both materialized and summary-only modes.
126
+ const NodeThreadSummary* getThreadSummary(const ICFGNode* inst) const;
127
+
110
128
  /// Get interleaving thread for statement inst
111
129
  //@{
112
130
  inline const NodeBS& getInterleavingThreads(const CxtThreadStmt& cts)
@@ -137,16 +155,22 @@ public:
137
155
  void printInterleaving();
138
156
 
139
157
  protected:
158
+ /// Construction is paired with ForkJoinAnalysis initialization by create().
159
+ /// @param representation Keep per-context copies
160
+ /// for clients that enumerate raw states (the pre-analysis detector and
161
+ /// slicer). Main-phase clients issue only MHP queries and can use the exact
162
+ /// projected query summary instead.
163
+ explicit MHP(
164
+ TCT* t,
165
+ StateRepresentation representation = StateRepresentation::MaterializedContexts);
140
166
 
141
- inline const CallGraph::FunctionSet& getCallee(const CallICFGNode* inst, CallGraph::FunctionSet& callees)
142
- {
143
- tcg->getCallees(inst, callees);
144
- return callees;
145
- }
146
167
  /// Update non-candidate functions' interleaving.
147
168
  /// Copy interleaving threads of the entry inst to other insts.
148
169
  template<class ICFGGraph, class CGGraph> void updateNonCandidateFunInterleaving(ICFGGraph icfg, CGGraph cg);
149
170
 
171
+ /// Build the exact, context-compressed representation used by repeated MHP
172
+ /// queries after the context-sensitive fixed point has converged.
173
+ template<class ICFGGraph, class CGGraph> void buildQuerySummaries(ICFGGraph icfg, CGGraph cg);
150
174
  /// Handle non-candidate function
151
175
  template<class ICFGGraph, class CGGraph> void handleNonCandidateFun(ICFGGraph icfg, CGGraph cg, const CxtThreadStmt& cts);
152
176
 
@@ -302,6 +326,9 @@ protected:
302
326
  BBToSymJoinsMap bbToSymJoins; ///< loop block -> symmetric in-loop joins of that loop
303
327
  SymJoinToLoopMap symJoinLoop; ///< symmetric in-loop join -> its loop's blocks
304
328
  InstToThreadStmtSetMap instToTSMap; ///< Map an instruction to its ThreadStmtSet
329
+ InstToThreadSummaryMap instToThreadSummary; ///< Exact per-node/per-tid query compression
330
+ Map<const ICFGNode*, const ICFGNode*> querySummaryOwner; ///< Non-candidate node -> entry summary
331
+ StateRepresentation stateRepresentation;
305
332
  FuncPairToBool nonCandidateFuncMHPRelMap;
306
333
 
307
334
  public:
@@ -347,7 +374,8 @@ public:
347
374
  /// context-sensitive forward traversal from each fork site. Generate following results
348
375
  /// (1) fork join pair, maps a context-sensitive join site to its corresponding thread ids
349
376
  /// (2) never happen-in-parallel thread pairs
350
- void analyzeForkJoinPair();
377
+ template<class ICFGGraph, class CGGraph>
378
+ void analyzeForkJoinPair(ICFGGraph icfg, CGGraph cg);
351
379
 
352
380
  /// Get directly joined threadIDs based on a context-sensitive join site
353
381
  inline NodeBS& getDirectlyJoinedTid(const CxtStmt& cs)
@@ -401,19 +429,27 @@ public:
401
429
  private:
402
430
 
403
431
  /// Handle fork
404
- void handleFork(const CxtStmt& cts,NodeID rootTid);
432
+ template<class ICFGGraph, class CGGraph>
433
+ void handleFork(ICFGGraph icfg, CGGraph cg,
434
+ const CxtStmt& cts, NodeID rootTid);
405
435
 
406
436
  /// Handle join
407
- void handleJoin(const CxtStmt& cts,NodeID rootTid);
437
+ template<class ICFGGraph, class CGGraph>
438
+ void handleJoin(ICFGGraph icfg, CGGraph cg,
439
+ const CxtStmt& cts, NodeID rootTid);
408
440
 
409
441
  /// Handle call
410
- void handleCall(const CxtStmt& cts,NodeID rootTid);
442
+ template<class ICFGGraph, class CGGraph>
443
+ void handleCall(ICFGGraph icfg, CGGraph cg,
444
+ const CxtStmt& cts);
411
445
 
412
446
  /// Handle return
413
- void handleRet(const CxtStmt& cts);
447
+ template<class ICFGGraph, class CGGraph>
448
+ void handleRet(ICFGGraph icfg, CGGraph cg, const CxtStmt& cts);
414
449
 
415
450
  /// Handle intra
416
- void handleIntra(const CxtStmt& cts);
451
+ template<class ICFGGraph>
452
+ void handleIntra(ICFGGraph icfg, const CxtStmt& cts);
417
453
 
418
454
  /// Return true if the fork and join have the same SCEV
419
455
  bool isSameSCEV(const ICFGNode* forkSite, const ICFGNode* joinSite);
@@ -539,11 +575,6 @@ private:
539
575
  {
540
576
  return getTCG()->getThreadAPI()->getJoinedThread(call);
541
577
  }
542
- inline const CallGraph::FunctionSet& getCallee(const ICFGNode* inst, CallGraph::FunctionSet& callees)
543
- {
544
- getTCG()->getCallees(SVFUtil::cast<CallICFGNode>(inst), callees);
545
- return callees;
546
- }
547
578
  /// ThreadCallGraph
548
579
  inline ThreadCallGraph* getTCG() const
549
580
  {
@@ -611,6 +642,16 @@ private:
611
642
  InstToCxtStmt instToCxtStmt; ///<Map a statement to all its context-sensitive statements
612
643
  };
613
644
 
645
+ template<class ICFGGraph, class CGGraph>
646
+ std::unique_ptr<MHP> MHP::create(
647
+ TCT* t, ICFGGraph icfg, CGGraph cg, StateRepresentation representation)
648
+ {
649
+ std::unique_ptr<MHP> mhp(new MHP(t, representation));
650
+ mhp->fja->analyzeForkJoinPair(icfg, cg);
651
+ mhp->buildSymJoinKillTables();
652
+ return mhp;
653
+ }
654
+
614
655
  } // End namespace SVF
615
656
 
616
657
  #endif /* MHP_H_ */