svf-lib 1.0.2437 → 1.0.2439

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.
@@ -72,13 +72,11 @@ public:
72
72
  typedef Map<CxtLock, LockSpan> CxtLockToSpan;
73
73
  typedef Map<CxtLock, NodeBS> CxtLockToLockSet;
74
74
  typedef Map<const ICFGNode*, NodeBS> LockSiteToLockSet;
75
- typedef Map<const ICFGNode*, LockSpan> InstToCxtStmtSet;
75
+ typedef Map<const ICFGNode*, CxtStmtSet> InstToCxtStmtSet;
76
76
  typedef Map<CxtStmt, CxtLockSet> CxtStmtToCxtLockSet;
77
77
  typedef FIFOWorkList<CxtLockProc> CxtLockProcVec;
78
78
  typedef Set<CxtLockProc> CxtLockProcSet;
79
79
 
80
- typedef Map<const ICFGNode*, CxtStmtSet> InstToCxtStmt;
81
-
82
80
  LockAnalysis(TCT* t) : tct(t), lockTime(0),numOfTotalQueries(0), numOfLockedQueries(0), lockQueriesTime(0)
83
81
  {
84
82
  }
@@ -200,12 +198,12 @@ public:
200
198
  /// Context-sensitive statement and lock spans
201
199
  //@{
202
200
  /// Get LockSet and LockSpan
203
- inline bool hasCxtStmtfromInst(const ICFGNode* inst) const
201
+ inline bool hasCxtStmtFromInst(const ICFGNode* inst) const
204
202
  {
205
203
  InstToCxtStmtSet::const_iterator it = instToCxtStmtSet.find(inst);
206
204
  return (it != instToCxtStmtSet.end());
207
205
  }
208
- inline const CxtStmtSet& getCxtStmtfromInst(const ICFGNode* inst) const
206
+ inline const CxtStmtSet& getCxtStmtsFromInst(const ICFGNode* inst) const
209
207
  {
210
208
  InstToCxtStmtSet::const_iterator it = instToCxtStmtSet.find(inst);
211
209
  assert(it != instToCxtStmtSet.end());
@@ -271,9 +269,9 @@ public:
271
269
  /// Check if one instruction's context stmt is in a lock span
272
270
  inline bool hasOneCxtInLockSpan(const ICFGNode *I, LockSpan lspan) const
273
271
  {
274
- if(!hasCxtStmtfromInst(I))
272
+ if(!hasCxtStmtFromInst(I))
275
273
  return false;
276
- const LockSpan ctsset = getCxtStmtfromInst(I);
274
+ const LockSpan ctsset = getCxtStmtsFromInst(I);
277
275
  for (LockSpan::const_iterator cts = ctsset.begin(), ects = ctsset.end(); cts != ects; cts++)
278
276
  {
279
277
  if(lspan.find(*cts) != lspan.end())
@@ -286,9 +284,9 @@ public:
286
284
 
287
285
  inline bool hasAllCxtInLockSpan(const ICFGNode *I, LockSpan lspan) const
288
286
  {
289
- if(!hasCxtStmtfromInst(I))
287
+ if(!hasCxtStmtFromInst(I))
290
288
  return false;
291
- const LockSpan ctsset = getCxtStmtfromInst(I);
289
+ const LockSpan ctsset = getCxtStmtsFromInst(I);
292
290
  for (LockSpan::const_iterator cts = ctsset.begin(), ects = ctsset.end(); cts != ects; cts++)
293
291
  {
294
292
  if (lspan.find(*cts) == lspan.end())
@@ -429,10 +427,15 @@ private:
429
427
  }
430
428
  //@}
431
429
 
430
+ /// Context helper functions
431
+ //@{
432
432
  /// Push calling context
433
433
  void pushCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee);
434
434
  /// Match context
435
435
  bool matchCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee);
436
+ /// If lhs is a suffix of rhs, including equal
437
+ bool isContextSuffix(const CallStrCxt& lhs, const CallStrCxt& call);
438
+ //@}
436
439
 
437
440
  /// Whether it is a lock site
438
441
  inline bool isTDFork(const ICFGNode* call)
@@ -96,11 +96,11 @@ public:
96
96
  //@{
97
97
  inline const NodeBS& getInterleavingThreads(const CxtThreadStmt& cts)
98
98
  {
99
- return threadStmtToTheadInterLeav[cts];
99
+ return threadStmtToThreadInterLeav[cts];
100
100
  }
101
101
  inline bool hasInterleavingThreads(const CxtThreadStmt& cts) const
102
102
  {
103
- return threadStmtToTheadInterLeav.find(cts)!=threadStmtToTheadInterLeav.end();
103
+ return threadStmtToThreadInterLeav.find(cts)!=threadStmtToThreadInterLeav.end();
104
104
  }
105
105
  //@}
106
106
 
@@ -154,7 +154,7 @@ private:
154
154
  //@{
155
155
  inline void addInterleavingThread(const CxtThreadStmt& tgr, NodeID tid)
156
156
  {
157
- if(threadStmtToTheadInterLeav[tgr].test_and_set(tid))
157
+ if(threadStmtToThreadInterLeav[tgr].test_and_set(tid))
158
158
  {
159
159
  instToTSMap[tgr.getStmt()].insert(tgr);
160
160
  pushToCTSWorkList(tgr);
@@ -162,7 +162,7 @@ private:
162
162
  }
163
163
  inline void addInterleavingThread(const CxtThreadStmt& tgr, const CxtThreadStmt& src)
164
164
  {
165
- bool changed = threadStmtToTheadInterLeav[tgr] |= threadStmtToTheadInterLeav[src];
165
+ bool changed = threadStmtToThreadInterLeav[tgr] |= threadStmtToThreadInterLeav[src];
166
166
  if(changed)
167
167
  {
168
168
  instToTSMap[tgr.getStmt()].insert(tgr);
@@ -177,7 +177,7 @@ private:
177
177
  if(isMustJoin(tgr.getTid(),joinsite))
178
178
  joinedTids.set(*it);
179
179
  }
180
- if(threadStmtToTheadInterLeav[tgr].intersectWithComplement(joinedTids))
180
+ if(threadStmtToThreadInterLeav[tgr].intersectWithComplement(joinedTids))
181
181
  {
182
182
  pushToCTSWorkList(tgr);
183
183
  }
@@ -201,16 +201,28 @@ private:
201
201
  {
202
202
  return tct->getTCTNode(curTid)->isMultiforked();
203
203
  }
204
+
205
+ /// Context helper functions
206
+ //@{
204
207
  /// Push calling context
205
208
  inline void pushCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
206
209
  {
210
+ /// handle calling context for candidate functions only
211
+ if(tct->isCandidateFun(call->getFun()) == false)
212
+ return;
207
213
  tct->pushCxt(cxt,call,callee);
208
214
  }
209
215
  /// Match context
210
- inline bool matchCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
216
+ inline bool matchAndPopCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
217
+ {
218
+ return tct->matchAndPopCxt(cxt,call,callee);
219
+ }
220
+ /// If lhs is a suffix of rhs, including equal
221
+ inline bool isContextSuffix(const CallStrCxt& lhs, const CallStrCxt call)
211
222
  {
212
- return tct->matchCxt(cxt,call,callee);
223
+ return tct->isContextSuffix(lhs,call);
213
224
  }
225
+ //@}
214
226
 
215
227
  /// WorkList helper functions
216
228
  //@{
@@ -253,7 +265,7 @@ private:
253
265
  TCT* tct; ///< TCT
254
266
  ForkJoinAnalysis* fja; ///< ForJoin Analysis
255
267
  CxtThreadStmtWorkList cxtStmtList; ///< CxtThreadStmt worklist
256
- ThreadStmtToThreadInterleav threadStmtToTheadInterLeav; /// Map a statement to its thread interleavings
268
+ ThreadStmtToThreadInterleav threadStmtToThreadInterLeav; /// Map a statement to its thread interleavings
257
269
  InstToThreadStmtSetMap instToTSMap; ///< Map an instruction to its ThreadStmtSet
258
270
  FuncPairToBool nonCandidateFuncMHPRelMap;
259
271
 
@@ -290,6 +302,10 @@ public:
290
302
  typedef Map<CxtStmt, LoopBBs> CxtStmtToLoopMap;
291
303
  typedef FIFOWorkList<CxtStmt> CxtStmtWorkList;
292
304
 
305
+ typedef Set<CxtStmt> CxtStmtSet;
306
+ typedef Map<const ICFGNode*, CxtStmtSet> InstToCxtStmt;
307
+
308
+
293
309
  ForkJoinAnalysis(TCT* t) : tct(t)
294
310
  {
295
311
  collectSCEVInfo();
@@ -337,15 +353,6 @@ public:
337
353
  return full && !partial;
338
354
  }
339
355
 
340
- /// Get exit instruction of the start routine function of tid's parent thread
341
- inline const ICFGNode* getExitInstOfParentRoutineFun(NodeID tid) const
342
- {
343
- NodeID parentTid = tct->getParentThread(tid);
344
- const CxtThread& parentct = tct->getTCTNode(parentTid)->getCxtThread();
345
- const FunObjVar* parentRoutine = tct->getStartRoutineOfCxtThread(parentct);
346
- return parentRoutine->getExitBB()->back();
347
- }
348
-
349
356
  /// Get loop for join site
350
357
  inline LoopBBs& getJoinLoop(const CallICFGNode* inst)
351
358
  {
@@ -381,7 +388,7 @@ private:
381
388
  /// Whether it is a matched fork join pair
382
389
  bool isAliasedForkJoin(const CallICFGNode* forkSite, const CallICFGNode* joinSite)
383
390
  {
384
- return tct->getPTA()->alias(getForkedThread(forkSite)->getId(), getJoinedThread(joinSite)->getId()) && isSameSCEV(forkSite,joinSite);
391
+ return tct->getPTA()->alias(getForkedThread(forkSite)->getId(), getJoinedThread(joinSite)->getId());
385
392
  }
386
393
  /// Mark thread flags for cxtStmt
387
394
  //@{
@@ -403,7 +410,11 @@ private:
403
410
  ValDomain flag_tgr = getMarkedFlag(tgr);
404
411
  cxtStmtToAliveFlagMap[tgr] = flag;
405
412
  if(flag_tgr!=getMarkedFlag(tgr))
413
+ {
414
+ instToCxtStmt[tgr.getStmt()].insert(tgr);
406
415
  pushToCTSWorkList(tgr);
416
+ }
417
+
407
418
  }
408
419
  /// Transfer function for marking context-sensitive statement
409
420
  void markCxtStmtFlag(const CxtStmt& tgr, const CxtStmt& src)
@@ -425,6 +436,7 @@ private:
425
436
  }
426
437
  if(flag_tgr!=getMarkedFlag(tgr))
427
438
  {
439
+ instToCxtStmt[tgr.getStmt()].insert(tgr);
428
440
  pushToCTSWorkList(tgr);
429
441
  }
430
442
  }
@@ -449,16 +461,27 @@ private:
449
461
  }
450
462
  //@}
451
463
 
464
+ /// Context helper functions
465
+ //@{
452
466
  /// Push calling context
453
467
  inline void pushCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
454
468
  {
469
+ /// handle calling context for candidate functions only
470
+ if(tct->isCandidateFun(call->getFun()) == false)
471
+ return;
455
472
  tct->pushCxt(cxt,call,callee);
456
473
  }
457
474
  /// Match context
458
- inline bool matchCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
475
+ inline bool matchAndPopCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
476
+ {
477
+ return tct->matchAndPopCxt(cxt,call,callee);
478
+ }
479
+ /// If lhs is a suffix of rhs, including equal
480
+ inline bool isContextSuffix(const CallStrCxt& lhs, const CallStrCxt call)
459
481
  {
460
- return tct->matchCxt(cxt,call,callee);
482
+ return tct->isContextSuffix(lhs,call);
461
483
  }
484
+ //@}
462
485
 
463
486
  /// Whether it is a fork site
464
487
  inline bool isTDFork(const ICFGNode* call)
@@ -524,6 +547,18 @@ private:
524
547
  }
525
548
  //@}
526
549
 
550
+ /// Get CxtStmtSet for an instruction
551
+ inline const CxtStmtSet& getCxtStmtsFromInst(const ICFGNode* inst) const
552
+ {
553
+ InstToCxtStmt::const_iterator it = instToCxtStmt.find(inst);
554
+ assert(it!=instToCxtStmt.end() && "no CxtStmt for the instruction?");
555
+ return it->second;
556
+ }
557
+ inline bool hasCxtStmtsFromInst(const ICFGNode* inst) const
558
+ {
559
+ return instToCxtStmt.find(inst)!=instToCxtStmt.end();
560
+ }
561
+
527
562
  /// Add inloop join
528
563
  inline void addSymmetricLoopJoin(const CxtStmt& cs, LoopBBs& lp)
529
564
  {
@@ -539,6 +574,7 @@ private:
539
574
  ThreadPairSet HPPair; ///< threads happen-in-parallel
540
575
  ThreadPairSet fullJoin; ///< t1 fully joins t2 along all program path
541
576
  ThreadPairSet partialJoin; ///< t1 partially joins t2 along some program path(s)
577
+ InstToCxtStmt instToCxtStmt; ///<Map a statement to all its context-sensitive statements
542
578
  };
543
579
 
544
580
  } // End namespace SVF
@@ -66,7 +66,7 @@ public:
66
66
  /// We start the pass here
67
67
  virtual bool runOnModule(SVFIR* module);
68
68
  /// Compute MHP
69
- virtual MHP* computeMHP();
69
+ virtual MHP* computeMHP(TCT* tct);
70
70
  /// Compute locksets
71
71
  virtual LockAnalysis* computeLocksets(TCT* tct);
72
72
  /// Perform detection
@@ -97,7 +97,7 @@ public:
97
97
  SVFUtil::outs() << "---\ntid: " << this->getId() << " inloop:" << ctx.isInloop() << " incycle:" << ctx.isIncycle() << " multiforked:"<< isMultiforked();
98
98
  }
99
99
 
100
- /// Get CxtThread
100
+ /// Get thread creation context, <fork site, call string context>
101
101
  inline const CxtThread& getCxtThread() const
102
102
  {
103
103
  return ctx;
@@ -142,7 +142,7 @@ public:
142
142
 
143
143
 
144
144
  private:
145
- const CxtThread ctx;
145
+ const CxtThread ctx; /// Thread creation context, <fork site, call string context>
146
146
  bool multiforked;
147
147
  };
148
148
 
@@ -162,7 +162,8 @@ public:
162
162
  typedef Set<const ICFGNode*> InstSet;
163
163
  typedef Set<const CallGraphNode*> PTACGNodeSet;
164
164
  typedef Map<CxtThread,TCTNode*> CxtThreadToNodeMap;
165
- typedef Map<CxtThread,CallStrCxt> CxtThreadToForkCxt;
165
+ typedef Set<std::pair<NodeID, CallStrCxt>> CallStrCxtSet;
166
+ typedef Map<CxtThread,CallStrCxtSet> CxtThreadToForkCxtSet;
166
167
  typedef Map<CxtThread,const FunObjVar*> CxtThreadToFun;
167
168
  typedef Map<const ICFGNode*, LoopBBs> InstToLoopMap;
168
169
  typedef FIFOWorkList<CxtThreadProc> CxtThreadProcVec;
@@ -172,7 +173,8 @@ public:
172
173
  /// Constructor
173
174
  TCT(PointerAnalysis* p) :pta(p),TCTNodeNum(0),TCTEdgeNum(0),MaxCxtSize(0)
174
175
  {
175
- tcg = SVFUtil::cast<ThreadCallGraph>(pta->getCallGraph());
176
+ tcg = SVFUtil::dyn_cast<ThreadCallGraph>(pta->getCallGraph());
177
+ assert(tcg != nullptr && "TCT::TCT: call graph is not a ThreadCallGraph!");
176
178
  tcg->updateCallGraph(pta);
177
179
  //tcg->updateJoinEdge(pta);
178
180
  tcgSCC = pta->getCallGraphSCC();
@@ -182,9 +184,7 @@ public:
182
184
 
183
185
  /// Destructor
184
186
  virtual ~TCT()
185
- {
186
- destroy();
187
- }
187
+ { }
188
188
 
189
189
  /// Get TCG
190
190
  inline ThreadCallGraph* getThreadCallGraph() const
@@ -310,24 +310,29 @@ public:
310
310
  const TCTNode* node = getTCTNode(tid);
311
311
  return node->getInEdges().size()==1;
312
312
  }
313
- /// Get parent thread
314
- inline NodeID getParentThread(NodeID tid) const
313
+ /// Get parent threads
314
+ inline NodeBS getParentThreads(NodeID tid) const
315
315
  {
316
+ NodeBS parentTds;
316
317
  const TCTNode* node = getTCTNode(tid);
317
- assert(node->getInEdges().size()<=1 && "should have at most one parent thread");
318
- assert(node->getInEdges().size()==1 && "does not have a parent thread");
319
- const TCTEdge* edge = *(node->getInEdges().begin());
320
- return edge->getSrcID();
318
+ assert(node->getInEdges().size()>=1 && "does not have a parent thread");
319
+
320
+ for (const TCTEdge* edge : node->getInEdges())
321
+ {
322
+ parentTds.set(edge->getSrcID());
323
+ }
324
+ return parentTds;
321
325
  }
322
326
  /// Get all ancestor threads
323
- const NodeBS getAncestorThread(NodeID tid) const
327
+ const NodeBS getAncestorThreads(NodeID tid) const
324
328
  {
325
329
  NodeBS tds;
326
330
  if(hasParentThread(tid) == false)
327
331
  return tds;
328
332
 
329
333
  FIFOWorkList<NodeID> worklist;
330
- worklist.push(getParentThread(tid));
334
+ for(NodeID parentTid : getParentThreads(tid))
335
+ worklist.push(parentTid);
331
336
 
332
337
  while(!worklist.empty())
333
338
  {
@@ -335,7 +340,8 @@ public:
335
340
  if(tds.test_and_set(t))
336
341
  {
337
342
  if(hasParentThread(t))
338
- worklist.push(getParentThread(t));
343
+ for(NodeID parentTid : getParentThreads(t))
344
+ worklist.push(parentTid);
339
345
  }
340
346
  }
341
347
  return tds;
@@ -346,24 +352,26 @@ public:
346
352
  NodeBS tds;
347
353
  if(hasParentThread(tid) == false)
348
354
  return tds;
349
-
350
- const TCTNode* node = getTCTNode(getParentThread(tid));
351
- for(ThreadCreateEdgeSet::const_iterator it = getChildrenBegin(node), eit = getChildrenEnd(node); it!=eit; ++it)
355
+ for (NodeID parentTid : getParentThreads(tid))
352
356
  {
353
- NodeID child = (*it)->getDstNode()->getId();
354
- if(child!=tid)
355
- tds.set(child);
357
+ const TCTNode* parentNode = getTCTNode(parentTid);
358
+ for(ThreadCreateEdgeSet::const_iterator it = getChildrenBegin(parentNode),
359
+ eit = getChildrenEnd(parentNode); it!=eit; ++it)
360
+ {
361
+ NodeID child = (*it)->getDstNode()->getId();
362
+ if(child!=tid)
363
+ tds.set(child);
364
+ }
356
365
  }
357
-
358
366
  return tds;
359
367
  }
360
368
  //@}
361
369
 
362
- /// get the context of a thread at its spawning site (fork site)
363
- const CallStrCxt& getCxtOfCxtThread(const CxtThread& ct) const
370
+ /// get the contexts of a thread at its spawning sites (fork sites)
371
+ const CallStrCxtSet& getCxtOfCxtThread(const CxtThread& ct) const
364
372
  {
365
- CxtThreadToForkCxt::const_iterator it = ctToForkCxtMap.find(ct);
366
- assert(it!=ctToForkCxtMap.end() && "Cxt Thread not found!!");
373
+ CxtThreadToForkCxtSet::const_iterator it = ctToForkCxtsMap.find(ct);
374
+ assert(it!=ctToForkCxtsMap.end() && "Cxt Thread not found!!");
367
375
  return it->second;
368
376
  }
369
377
 
@@ -407,17 +415,16 @@ public:
407
415
  /// Get loop for fork/join site
408
416
  const LoopBBs& getLoop(const SVFBasicBlock* bb);
409
417
 
418
+ /// Context helper functions
419
+ //@{
410
420
  /// Push calling context
411
421
  void pushCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee);
412
422
  /// Match context
413
- bool matchCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee);
423
+ bool matchAndPopCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee);
424
+ /// If lhs is a suffix of rhs, including equal
425
+ bool isContextSuffix(const CallStrCxt& lhs, const CallStrCxt& call);
426
+ //@}
414
427
 
415
- inline void pushCxt(CallStrCxt& cxt, CallSiteID csId)
416
- {
417
- cxt.push_back(csId);
418
- if (cxt.size() > MaxCxtSize)
419
- MaxCxtSize = cxt.size();
420
- }
421
428
  /// Whether a join site is in recursion
422
429
  inline bool isJoinSiteInRecursion(const CallICFGNode* join) const
423
430
  {
@@ -504,7 +511,7 @@ private:
504
511
 
505
512
  /// Get or create a tct node based on CxtThread
506
513
  //@{
507
- inline TCTNode* getOrCreateTCTNode(const CallStrCxt& cxt, const ICFGNode* fork,const CallStrCxt& oldCxt, const FunObjVar* routine)
514
+ inline TCTNode* getOrCreateTCTNode(const CallStrCxt& cxt, const ICFGNode* fork, const CxtThreadProc& forkSiteCtp, const FunObjVar* routine)
508
515
  {
509
516
  CxtThread ct(cxt,fork);
510
517
  CxtThreadToNodeMap::const_iterator it = ctpToNodeMap.find(ct);
@@ -513,7 +520,7 @@ private:
513
520
  return it->second;
514
521
  }
515
522
 
516
- addCxtOfCxtThread(oldCxt,ct);
523
+ addCxtOfCxtThread(forkSiteCtp.getTid(), forkSiteCtp.getContext(), ct);
517
524
  addStartRoutineOfCxtThread(routine,ct);
518
525
 
519
526
  setMultiForkedAttrs(ct);
@@ -540,10 +547,11 @@ private:
540
547
  }
541
548
 
542
549
  /// Add context for a thread at its spawning site (fork site)
543
- void addCxtOfCxtThread(const CallStrCxt& cxt, const CxtThread& ct)
550
+ void addCxtOfCxtThread(NodeID pTid, const CallStrCxt& cxt, const CxtThread& ct)
544
551
  {
545
- ctToForkCxtMap[ct] = cxt;
552
+ ctToForkCxtsMap[ct].insert(std::make_pair(pTid, cxt));
546
553
  }
554
+
547
555
  /// Add start routine function of a cxt thread
548
556
  void addStartRoutineOfCxtThread(const FunObjVar* fun, const CxtThread& ct)
549
557
  {
@@ -571,13 +579,6 @@ private:
571
579
  return visitedCTPs.find(ctp)!=visitedCTPs.end();
572
580
  }
573
581
  //@}
574
- /// Clean up memory
575
- inline void destroy()
576
- {
577
- if(tcgSCC)
578
- delete tcgSCC;
579
- tcgSCC=nullptr;
580
- }
581
582
 
582
583
  FunSet entryFuncSet; /// Procedures that are neither called by other functions nor extern functions
583
584
  FunSet candidateFuncSet; /// Procedures we care about during call graph traversing when creating TCT
@@ -585,7 +586,7 @@ private:
585
586
  CxtThreadProcVec ctpList; /// CxtThreadProc List
586
587
  CxtThreadProcSet visitedCTPs; /// Record all visited ctps
587
588
  CxtThreadToNodeMap ctpToNodeMap; /// Map a ctp to its graph node
588
- CxtThreadToForkCxt ctToForkCxtMap; /// Map a CxtThread to the context at its spawning site (fork site).
589
+ CxtThreadToForkCxtSet ctToForkCxtsMap; /// Map a CxtThread to the context at its spawning site (fork site).
589
590
  CxtThreadToFun ctToRoutineFunMap; /// Map a CxtThread to its start routine function.
590
591
  InstToLoopMap joinSiteToLoopMap; ///< map an inloop join to its loop class
591
592
  Set<const ICFGNode*> inRecurJoinSites; ///< Fork or Join sites in recursions
@@ -72,13 +72,11 @@ public:
72
72
  typedef Map<CxtLock, LockSpan> CxtLockToSpan;
73
73
  typedef Map<CxtLock, NodeBS> CxtLockToLockSet;
74
74
  typedef Map<const ICFGNode*, NodeBS> LockSiteToLockSet;
75
- typedef Map<const ICFGNode*, LockSpan> InstToCxtStmtSet;
75
+ typedef Map<const ICFGNode*, CxtStmtSet> InstToCxtStmtSet;
76
76
  typedef Map<CxtStmt, CxtLockSet> CxtStmtToCxtLockSet;
77
77
  typedef FIFOWorkList<CxtLockProc> CxtLockProcVec;
78
78
  typedef Set<CxtLockProc> CxtLockProcSet;
79
79
 
80
- typedef Map<const ICFGNode*, CxtStmtSet> InstToCxtStmt;
81
-
82
80
  LockAnalysis(TCT* t) : tct(t), lockTime(0),numOfTotalQueries(0), numOfLockedQueries(0), lockQueriesTime(0)
83
81
  {
84
82
  }
@@ -200,12 +198,12 @@ public:
200
198
  /// Context-sensitive statement and lock spans
201
199
  //@{
202
200
  /// Get LockSet and LockSpan
203
- inline bool hasCxtStmtfromInst(const ICFGNode* inst) const
201
+ inline bool hasCxtStmtFromInst(const ICFGNode* inst) const
204
202
  {
205
203
  InstToCxtStmtSet::const_iterator it = instToCxtStmtSet.find(inst);
206
204
  return (it != instToCxtStmtSet.end());
207
205
  }
208
- inline const CxtStmtSet& getCxtStmtfromInst(const ICFGNode* inst) const
206
+ inline const CxtStmtSet& getCxtStmtsFromInst(const ICFGNode* inst) const
209
207
  {
210
208
  InstToCxtStmtSet::const_iterator it = instToCxtStmtSet.find(inst);
211
209
  assert(it != instToCxtStmtSet.end());
@@ -271,9 +269,9 @@ public:
271
269
  /// Check if one instruction's context stmt is in a lock span
272
270
  inline bool hasOneCxtInLockSpan(const ICFGNode *I, LockSpan lspan) const
273
271
  {
274
- if(!hasCxtStmtfromInst(I))
272
+ if(!hasCxtStmtFromInst(I))
275
273
  return false;
276
- const LockSpan ctsset = getCxtStmtfromInst(I);
274
+ const LockSpan ctsset = getCxtStmtsFromInst(I);
277
275
  for (LockSpan::const_iterator cts = ctsset.begin(), ects = ctsset.end(); cts != ects; cts++)
278
276
  {
279
277
  if(lspan.find(*cts) != lspan.end())
@@ -286,9 +284,9 @@ public:
286
284
 
287
285
  inline bool hasAllCxtInLockSpan(const ICFGNode *I, LockSpan lspan) const
288
286
  {
289
- if(!hasCxtStmtfromInst(I))
287
+ if(!hasCxtStmtFromInst(I))
290
288
  return false;
291
- const LockSpan ctsset = getCxtStmtfromInst(I);
289
+ const LockSpan ctsset = getCxtStmtsFromInst(I);
292
290
  for (LockSpan::const_iterator cts = ctsset.begin(), ects = ctsset.end(); cts != ects; cts++)
293
291
  {
294
292
  if (lspan.find(*cts) == lspan.end())
@@ -429,10 +427,15 @@ private:
429
427
  }
430
428
  //@}
431
429
 
430
+ /// Context helper functions
431
+ //@{
432
432
  /// Push calling context
433
433
  void pushCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee);
434
434
  /// Match context
435
435
  bool matchCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee);
436
+ /// If lhs is a suffix of rhs, including equal
437
+ bool isContextSuffix(const CallStrCxt& lhs, const CallStrCxt& call);
438
+ //@}
436
439
 
437
440
  /// Whether it is a lock site
438
441
  inline bool isTDFork(const ICFGNode* call)
@@ -96,11 +96,11 @@ public:
96
96
  //@{
97
97
  inline const NodeBS& getInterleavingThreads(const CxtThreadStmt& cts)
98
98
  {
99
- return threadStmtToTheadInterLeav[cts];
99
+ return threadStmtToThreadInterLeav[cts];
100
100
  }
101
101
  inline bool hasInterleavingThreads(const CxtThreadStmt& cts) const
102
102
  {
103
- return threadStmtToTheadInterLeav.find(cts)!=threadStmtToTheadInterLeav.end();
103
+ return threadStmtToThreadInterLeav.find(cts)!=threadStmtToThreadInterLeav.end();
104
104
  }
105
105
  //@}
106
106
 
@@ -154,7 +154,7 @@ private:
154
154
  //@{
155
155
  inline void addInterleavingThread(const CxtThreadStmt& tgr, NodeID tid)
156
156
  {
157
- if(threadStmtToTheadInterLeav[tgr].test_and_set(tid))
157
+ if(threadStmtToThreadInterLeav[tgr].test_and_set(tid))
158
158
  {
159
159
  instToTSMap[tgr.getStmt()].insert(tgr);
160
160
  pushToCTSWorkList(tgr);
@@ -162,7 +162,7 @@ private:
162
162
  }
163
163
  inline void addInterleavingThread(const CxtThreadStmt& tgr, const CxtThreadStmt& src)
164
164
  {
165
- bool changed = threadStmtToTheadInterLeav[tgr] |= threadStmtToTheadInterLeav[src];
165
+ bool changed = threadStmtToThreadInterLeav[tgr] |= threadStmtToThreadInterLeav[src];
166
166
  if(changed)
167
167
  {
168
168
  instToTSMap[tgr.getStmt()].insert(tgr);
@@ -177,7 +177,7 @@ private:
177
177
  if(isMustJoin(tgr.getTid(),joinsite))
178
178
  joinedTids.set(*it);
179
179
  }
180
- if(threadStmtToTheadInterLeav[tgr].intersectWithComplement(joinedTids))
180
+ if(threadStmtToThreadInterLeav[tgr].intersectWithComplement(joinedTids))
181
181
  {
182
182
  pushToCTSWorkList(tgr);
183
183
  }
@@ -201,16 +201,28 @@ private:
201
201
  {
202
202
  return tct->getTCTNode(curTid)->isMultiforked();
203
203
  }
204
+
205
+ /// Context helper functions
206
+ //@{
204
207
  /// Push calling context
205
208
  inline void pushCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
206
209
  {
210
+ /// handle calling context for candidate functions only
211
+ if(tct->isCandidateFun(call->getFun()) == false)
212
+ return;
207
213
  tct->pushCxt(cxt,call,callee);
208
214
  }
209
215
  /// Match context
210
- inline bool matchCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
216
+ inline bool matchAndPopCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
217
+ {
218
+ return tct->matchAndPopCxt(cxt,call,callee);
219
+ }
220
+ /// If lhs is a suffix of rhs, including equal
221
+ inline bool isContextSuffix(const CallStrCxt& lhs, const CallStrCxt call)
211
222
  {
212
- return tct->matchCxt(cxt,call,callee);
223
+ return tct->isContextSuffix(lhs,call);
213
224
  }
225
+ //@}
214
226
 
215
227
  /// WorkList helper functions
216
228
  //@{
@@ -253,7 +265,7 @@ private:
253
265
  TCT* tct; ///< TCT
254
266
  ForkJoinAnalysis* fja; ///< ForJoin Analysis
255
267
  CxtThreadStmtWorkList cxtStmtList; ///< CxtThreadStmt worklist
256
- ThreadStmtToThreadInterleav threadStmtToTheadInterLeav; /// Map a statement to its thread interleavings
268
+ ThreadStmtToThreadInterleav threadStmtToThreadInterLeav; /// Map a statement to its thread interleavings
257
269
  InstToThreadStmtSetMap instToTSMap; ///< Map an instruction to its ThreadStmtSet
258
270
  FuncPairToBool nonCandidateFuncMHPRelMap;
259
271
 
@@ -290,6 +302,10 @@ public:
290
302
  typedef Map<CxtStmt, LoopBBs> CxtStmtToLoopMap;
291
303
  typedef FIFOWorkList<CxtStmt> CxtStmtWorkList;
292
304
 
305
+ typedef Set<CxtStmt> CxtStmtSet;
306
+ typedef Map<const ICFGNode*, CxtStmtSet> InstToCxtStmt;
307
+
308
+
293
309
  ForkJoinAnalysis(TCT* t) : tct(t)
294
310
  {
295
311
  collectSCEVInfo();
@@ -337,15 +353,6 @@ public:
337
353
  return full && !partial;
338
354
  }
339
355
 
340
- /// Get exit instruction of the start routine function of tid's parent thread
341
- inline const ICFGNode* getExitInstOfParentRoutineFun(NodeID tid) const
342
- {
343
- NodeID parentTid = tct->getParentThread(tid);
344
- const CxtThread& parentct = tct->getTCTNode(parentTid)->getCxtThread();
345
- const FunObjVar* parentRoutine = tct->getStartRoutineOfCxtThread(parentct);
346
- return parentRoutine->getExitBB()->back();
347
- }
348
-
349
356
  /// Get loop for join site
350
357
  inline LoopBBs& getJoinLoop(const CallICFGNode* inst)
351
358
  {
@@ -381,7 +388,7 @@ private:
381
388
  /// Whether it is a matched fork join pair
382
389
  bool isAliasedForkJoin(const CallICFGNode* forkSite, const CallICFGNode* joinSite)
383
390
  {
384
- return tct->getPTA()->alias(getForkedThread(forkSite)->getId(), getJoinedThread(joinSite)->getId()) && isSameSCEV(forkSite,joinSite);
391
+ return tct->getPTA()->alias(getForkedThread(forkSite)->getId(), getJoinedThread(joinSite)->getId());
385
392
  }
386
393
  /// Mark thread flags for cxtStmt
387
394
  //@{
@@ -403,7 +410,11 @@ private:
403
410
  ValDomain flag_tgr = getMarkedFlag(tgr);
404
411
  cxtStmtToAliveFlagMap[tgr] = flag;
405
412
  if(flag_tgr!=getMarkedFlag(tgr))
413
+ {
414
+ instToCxtStmt[tgr.getStmt()].insert(tgr);
406
415
  pushToCTSWorkList(tgr);
416
+ }
417
+
407
418
  }
408
419
  /// Transfer function for marking context-sensitive statement
409
420
  void markCxtStmtFlag(const CxtStmt& tgr, const CxtStmt& src)
@@ -425,6 +436,7 @@ private:
425
436
  }
426
437
  if(flag_tgr!=getMarkedFlag(tgr))
427
438
  {
439
+ instToCxtStmt[tgr.getStmt()].insert(tgr);
428
440
  pushToCTSWorkList(tgr);
429
441
  }
430
442
  }
@@ -449,16 +461,27 @@ private:
449
461
  }
450
462
  //@}
451
463
 
464
+ /// Context helper functions
465
+ //@{
452
466
  /// Push calling context
453
467
  inline void pushCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
454
468
  {
469
+ /// handle calling context for candidate functions only
470
+ if(tct->isCandidateFun(call->getFun()) == false)
471
+ return;
455
472
  tct->pushCxt(cxt,call,callee);
456
473
  }
457
474
  /// Match context
458
- inline bool matchCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
475
+ inline bool matchAndPopCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
476
+ {
477
+ return tct->matchAndPopCxt(cxt,call,callee);
478
+ }
479
+ /// If lhs is a suffix of rhs, including equal
480
+ inline bool isContextSuffix(const CallStrCxt& lhs, const CallStrCxt call)
459
481
  {
460
- return tct->matchCxt(cxt,call,callee);
482
+ return tct->isContextSuffix(lhs,call);
461
483
  }
484
+ //@}
462
485
 
463
486
  /// Whether it is a fork site
464
487
  inline bool isTDFork(const ICFGNode* call)
@@ -524,6 +547,18 @@ private:
524
547
  }
525
548
  //@}
526
549
 
550
+ /// Get CxtStmtSet for an instruction
551
+ inline const CxtStmtSet& getCxtStmtsFromInst(const ICFGNode* inst) const
552
+ {
553
+ InstToCxtStmt::const_iterator it = instToCxtStmt.find(inst);
554
+ assert(it!=instToCxtStmt.end() && "no CxtStmt for the instruction?");
555
+ return it->second;
556
+ }
557
+ inline bool hasCxtStmtsFromInst(const ICFGNode* inst) const
558
+ {
559
+ return instToCxtStmt.find(inst)!=instToCxtStmt.end();
560
+ }
561
+
527
562
  /// Add inloop join
528
563
  inline void addSymmetricLoopJoin(const CxtStmt& cs, LoopBBs& lp)
529
564
  {
@@ -539,6 +574,7 @@ private:
539
574
  ThreadPairSet HPPair; ///< threads happen-in-parallel
540
575
  ThreadPairSet fullJoin; ///< t1 fully joins t2 along all program path
541
576
  ThreadPairSet partialJoin; ///< t1 partially joins t2 along some program path(s)
577
+ InstToCxtStmt instToCxtStmt; ///<Map a statement to all its context-sensitive statements
542
578
  };
543
579
 
544
580
  } // End namespace SVF
@@ -66,7 +66,7 @@ public:
66
66
  /// We start the pass here
67
67
  virtual bool runOnModule(SVFIR* module);
68
68
  /// Compute MHP
69
- virtual MHP* computeMHP();
69
+ virtual MHP* computeMHP(TCT* tct);
70
70
  /// Compute locksets
71
71
  virtual LockAnalysis* computeLocksets(TCT* tct);
72
72
  /// Perform detection
@@ -97,7 +97,7 @@ public:
97
97
  SVFUtil::outs() << "---\ntid: " << this->getId() << " inloop:" << ctx.isInloop() << " incycle:" << ctx.isIncycle() << " multiforked:"<< isMultiforked();
98
98
  }
99
99
 
100
- /// Get CxtThread
100
+ /// Get thread creation context, <fork site, call string context>
101
101
  inline const CxtThread& getCxtThread() const
102
102
  {
103
103
  return ctx;
@@ -142,7 +142,7 @@ public:
142
142
 
143
143
 
144
144
  private:
145
- const CxtThread ctx;
145
+ const CxtThread ctx; /// Thread creation context, <fork site, call string context>
146
146
  bool multiforked;
147
147
  };
148
148
 
@@ -162,7 +162,8 @@ public:
162
162
  typedef Set<const ICFGNode*> InstSet;
163
163
  typedef Set<const CallGraphNode*> PTACGNodeSet;
164
164
  typedef Map<CxtThread,TCTNode*> CxtThreadToNodeMap;
165
- typedef Map<CxtThread,CallStrCxt> CxtThreadToForkCxt;
165
+ typedef Set<std::pair<NodeID, CallStrCxt>> CallStrCxtSet;
166
+ typedef Map<CxtThread,CallStrCxtSet> CxtThreadToForkCxtSet;
166
167
  typedef Map<CxtThread,const FunObjVar*> CxtThreadToFun;
167
168
  typedef Map<const ICFGNode*, LoopBBs> InstToLoopMap;
168
169
  typedef FIFOWorkList<CxtThreadProc> CxtThreadProcVec;
@@ -172,7 +173,8 @@ public:
172
173
  /// Constructor
173
174
  TCT(PointerAnalysis* p) :pta(p),TCTNodeNum(0),TCTEdgeNum(0),MaxCxtSize(0)
174
175
  {
175
- tcg = SVFUtil::cast<ThreadCallGraph>(pta->getCallGraph());
176
+ tcg = SVFUtil::dyn_cast<ThreadCallGraph>(pta->getCallGraph());
177
+ assert(tcg != nullptr && "TCT::TCT: call graph is not a ThreadCallGraph!");
176
178
  tcg->updateCallGraph(pta);
177
179
  //tcg->updateJoinEdge(pta);
178
180
  tcgSCC = pta->getCallGraphSCC();
@@ -182,9 +184,7 @@ public:
182
184
 
183
185
  /// Destructor
184
186
  virtual ~TCT()
185
- {
186
- destroy();
187
- }
187
+ { }
188
188
 
189
189
  /// Get TCG
190
190
  inline ThreadCallGraph* getThreadCallGraph() const
@@ -310,24 +310,29 @@ public:
310
310
  const TCTNode* node = getTCTNode(tid);
311
311
  return node->getInEdges().size()==1;
312
312
  }
313
- /// Get parent thread
314
- inline NodeID getParentThread(NodeID tid) const
313
+ /// Get parent threads
314
+ inline NodeBS getParentThreads(NodeID tid) const
315
315
  {
316
+ NodeBS parentTds;
316
317
  const TCTNode* node = getTCTNode(tid);
317
- assert(node->getInEdges().size()<=1 && "should have at most one parent thread");
318
- assert(node->getInEdges().size()==1 && "does not have a parent thread");
319
- const TCTEdge* edge = *(node->getInEdges().begin());
320
- return edge->getSrcID();
318
+ assert(node->getInEdges().size()>=1 && "does not have a parent thread");
319
+
320
+ for (const TCTEdge* edge : node->getInEdges())
321
+ {
322
+ parentTds.set(edge->getSrcID());
323
+ }
324
+ return parentTds;
321
325
  }
322
326
  /// Get all ancestor threads
323
- const NodeBS getAncestorThread(NodeID tid) const
327
+ const NodeBS getAncestorThreads(NodeID tid) const
324
328
  {
325
329
  NodeBS tds;
326
330
  if(hasParentThread(tid) == false)
327
331
  return tds;
328
332
 
329
333
  FIFOWorkList<NodeID> worklist;
330
- worklist.push(getParentThread(tid));
334
+ for(NodeID parentTid : getParentThreads(tid))
335
+ worklist.push(parentTid);
331
336
 
332
337
  while(!worklist.empty())
333
338
  {
@@ -335,7 +340,8 @@ public:
335
340
  if(tds.test_and_set(t))
336
341
  {
337
342
  if(hasParentThread(t))
338
- worklist.push(getParentThread(t));
343
+ for(NodeID parentTid : getParentThreads(t))
344
+ worklist.push(parentTid);
339
345
  }
340
346
  }
341
347
  return tds;
@@ -346,24 +352,26 @@ public:
346
352
  NodeBS tds;
347
353
  if(hasParentThread(tid) == false)
348
354
  return tds;
349
-
350
- const TCTNode* node = getTCTNode(getParentThread(tid));
351
- for(ThreadCreateEdgeSet::const_iterator it = getChildrenBegin(node), eit = getChildrenEnd(node); it!=eit; ++it)
355
+ for (NodeID parentTid : getParentThreads(tid))
352
356
  {
353
- NodeID child = (*it)->getDstNode()->getId();
354
- if(child!=tid)
355
- tds.set(child);
357
+ const TCTNode* parentNode = getTCTNode(parentTid);
358
+ for(ThreadCreateEdgeSet::const_iterator it = getChildrenBegin(parentNode),
359
+ eit = getChildrenEnd(parentNode); it!=eit; ++it)
360
+ {
361
+ NodeID child = (*it)->getDstNode()->getId();
362
+ if(child!=tid)
363
+ tds.set(child);
364
+ }
356
365
  }
357
-
358
366
  return tds;
359
367
  }
360
368
  //@}
361
369
 
362
- /// get the context of a thread at its spawning site (fork site)
363
- const CallStrCxt& getCxtOfCxtThread(const CxtThread& ct) const
370
+ /// get the contexts of a thread at its spawning sites (fork sites)
371
+ const CallStrCxtSet& getCxtOfCxtThread(const CxtThread& ct) const
364
372
  {
365
- CxtThreadToForkCxt::const_iterator it = ctToForkCxtMap.find(ct);
366
- assert(it!=ctToForkCxtMap.end() && "Cxt Thread not found!!");
373
+ CxtThreadToForkCxtSet::const_iterator it = ctToForkCxtsMap.find(ct);
374
+ assert(it!=ctToForkCxtsMap.end() && "Cxt Thread not found!!");
367
375
  return it->second;
368
376
  }
369
377
 
@@ -407,17 +415,16 @@ public:
407
415
  /// Get loop for fork/join site
408
416
  const LoopBBs& getLoop(const SVFBasicBlock* bb);
409
417
 
418
+ /// Context helper functions
419
+ //@{
410
420
  /// Push calling context
411
421
  void pushCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee);
412
422
  /// Match context
413
- bool matchCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee);
423
+ bool matchAndPopCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee);
424
+ /// If lhs is a suffix of rhs, including equal
425
+ bool isContextSuffix(const CallStrCxt& lhs, const CallStrCxt& call);
426
+ //@}
414
427
 
415
- inline void pushCxt(CallStrCxt& cxt, CallSiteID csId)
416
- {
417
- cxt.push_back(csId);
418
- if (cxt.size() > MaxCxtSize)
419
- MaxCxtSize = cxt.size();
420
- }
421
428
  /// Whether a join site is in recursion
422
429
  inline bool isJoinSiteInRecursion(const CallICFGNode* join) const
423
430
  {
@@ -504,7 +511,7 @@ private:
504
511
 
505
512
  /// Get or create a tct node based on CxtThread
506
513
  //@{
507
- inline TCTNode* getOrCreateTCTNode(const CallStrCxt& cxt, const ICFGNode* fork,const CallStrCxt& oldCxt, const FunObjVar* routine)
514
+ inline TCTNode* getOrCreateTCTNode(const CallStrCxt& cxt, const ICFGNode* fork, const CxtThreadProc& forkSiteCtp, const FunObjVar* routine)
508
515
  {
509
516
  CxtThread ct(cxt,fork);
510
517
  CxtThreadToNodeMap::const_iterator it = ctpToNodeMap.find(ct);
@@ -513,7 +520,7 @@ private:
513
520
  return it->second;
514
521
  }
515
522
 
516
- addCxtOfCxtThread(oldCxt,ct);
523
+ addCxtOfCxtThread(forkSiteCtp.getTid(), forkSiteCtp.getContext(), ct);
517
524
  addStartRoutineOfCxtThread(routine,ct);
518
525
 
519
526
  setMultiForkedAttrs(ct);
@@ -540,10 +547,11 @@ private:
540
547
  }
541
548
 
542
549
  /// Add context for a thread at its spawning site (fork site)
543
- void addCxtOfCxtThread(const CallStrCxt& cxt, const CxtThread& ct)
550
+ void addCxtOfCxtThread(NodeID pTid, const CallStrCxt& cxt, const CxtThread& ct)
544
551
  {
545
- ctToForkCxtMap[ct] = cxt;
552
+ ctToForkCxtsMap[ct].insert(std::make_pair(pTid, cxt));
546
553
  }
554
+
547
555
  /// Add start routine function of a cxt thread
548
556
  void addStartRoutineOfCxtThread(const FunObjVar* fun, const CxtThread& ct)
549
557
  {
@@ -571,13 +579,6 @@ private:
571
579
  return visitedCTPs.find(ctp)!=visitedCTPs.end();
572
580
  }
573
581
  //@}
574
- /// Clean up memory
575
- inline void destroy()
576
- {
577
- if(tcgSCC)
578
- delete tcgSCC;
579
- tcgSCC=nullptr;
580
- }
581
582
 
582
583
  FunSet entryFuncSet; /// Procedures that are neither called by other functions nor extern functions
583
584
  FunSet candidateFuncSet; /// Procedures we care about during call graph traversing when creating TCT
@@ -585,7 +586,7 @@ private:
585
586
  CxtThreadProcVec ctpList; /// CxtThreadProc List
586
587
  CxtThreadProcSet visitedCTPs; /// Record all visited ctps
587
588
  CxtThreadToNodeMap ctpToNodeMap; /// Map a ctp to its graph node
588
- CxtThreadToForkCxt ctToForkCxtMap; /// Map a CxtThread to the context at its spawning site (fork site).
589
+ CxtThreadToForkCxtSet ctToForkCxtsMap; /// Map a CxtThread to the context at its spawning site (fork site).
589
590
  CxtThreadToFun ctToRoutineFunMap; /// Map a CxtThread to its start routine function.
590
591
  InstToLoopMap joinSiteToLoopMap; ///< map an inloop join to its loop class
591
592
  Set<const ICFGNode*> inRecurJoinSites; ///< Fork or Join sites in recursions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svf-lib",
3
- "version": "1.0.2437",
3
+ "version": "1.0.2439",
4
4
  "description": "SVF's npm support",
5
5
  "main": "index.js",
6
6
  "scripts": {