svf-tools 1.0.1171 → 1.0.1173

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svf-tools",
3
- "version": "1.0.1171",
3
+ "version": "1.0.1173",
4
4
  "description": "* <b>[TypeClone](https://github.com/SVF-tools/SVF/wiki/TypeClone) published in our [ECOOP paper](https://yuleisui.github.io/publications/ecoop20.pdf) is now available in SVF </b> * <b>SVF now uses a single script for its build. Just type [`source ./build.sh`](https://github.com/SVF-tools/SVF/blob/master/build.sh) in your terminal, that's it!</b> * <b>SVF now supports LLVM-10.0.0! </b> * <b>We thank [bsauce](https://github.com/bsauce) for writing a user manual of SVF ([link1](https://www.jianshu.com/p/068a08ec749c) and [link2](https://www.jianshu.com/p/777c30d4240e)) in Chinese </b> * <b>SVF now supports LLVM-9.0.0 (Thank [Byoungyoung Lee](https://github.com/SVF-tools/SVF/issues/142) for his help!). </b> * <b>SVF now supports a set of [field-sensitive pointer analyses](https://yuleisui.github.io/publications/sas2019a.pdf). </b> * <b>[Use SVF as an external lib](https://github.com/SVF-tools/SVF/wiki/Using-SVF-as-a-lib-in-your-own-tool) for your own project (Contributed by [Hongxu Chen](https://github.com/HongxuChen)). </b> * <b>SVF now supports LLVM-7.0.0. </b> * <b>SVF now supports Docker. [Try SVF in Docker](https://github.com/SVF-tools/SVF/wiki/Try-SVF-in-Docker)! </b> * <b>SVF now supports [LLVM-6.0.0](https://github.com/svf-tools/SVF/pull/38) (Contributed by [Jack Anthony](https://github.com/jackanth)). </b> * <b>SVF now supports [LLVM-4.0.0](https://github.com/svf-tools/SVF/pull/23) (Contributed by Jared Carlson. Thank [Jared](https://github.com/jcarlson23) and [Will](https://github.com/dtzWill) for their in-depth [discussions](https://github.com/svf-tools/SVF/pull/18) about updating SVF!) </b> * <b>SVF now supports analysis for C++ programs.</b> <br />",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -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
@@ -376,7 +376,7 @@ void LockAnalysis::analyzeLockSpanCxtStmt()
376
376
  {
377
377
  handleCall(cts);
378
378
  }
379
- else if (isRetInstNode(curInst))
379
+ else if (SVFUtil::dyn_cast<FunExitICFGNode>(curInst))
380
380
  {
381
381
  handleRet(cts);
382
382
  }
@@ -472,10 +472,21 @@ void LockAnalysis::handleRet(const CxtStmt& cts)
472
472
  {
473
473
  for(const ICFGEdge* outEdge : curInst->getOutEdges())
474
474
  {
475
- if(outEdge->getDstNode()->getFun() == curInst->getFun())
475
+ if(outEdge->getDstNode()->getFun() == inst->getFun())
476
476
  {
477
- CxtStmt newCts(newCxt, outEdge->getDstNode());
478
- markCxtStmtFlag(newCts, cts);
477
+ // Iterate over callSite's call string context and use as the successor's context
478
+ if (!hasCxtStmtFromInst(*cit))
479
+ continue;
480
+ for (const CxtStmt& cxtStmt: getCxtStmtsFromInst(*cit))
481
+ {
482
+ CallStrCxt callSiteCxt = cxtStmt.getContext();
483
+ // If new context is a suffix of the call site context
484
+ if (isContextSuffix(newCxt, callSiteCxt))
485
+ {
486
+ CxtStmt newCts(callSiteCxt, outEdge->getDstNode());
487
+ markCxtStmtFlag(newCts, cts);
488
+ }
489
+ }
479
490
  }
480
491
  }
481
492
  }
@@ -489,10 +500,21 @@ void LockAnalysis::handleRet(const CxtStmt& cts)
489
500
  {
490
501
  for(const ICFGEdge* outEdge : curInst->getOutEdges())
491
502
  {
492
- if(outEdge->getDstNode()->getFun() == curInst->getFun())
503
+ if(outEdge->getDstNode()->getFun() == inst->getFun())
493
504
  {
494
- CxtStmt newCts(newCxt, outEdge->getDstNode());
495
- markCxtStmtFlag(newCts, cts);
505
+ // Iterate over callSite's call string context and use as the successor's context
506
+ if (!hasCxtStmtFromInst(*cit))
507
+ continue;
508
+ for (const CxtStmt& cxtStmt: getCxtStmtsFromInst(*cit))
509
+ {
510
+ CallStrCxt callSiteCxt = cxtStmt.getContext();
511
+ // If new context is a suffix of the call site context
512
+ if (isContextSuffix(newCxt, callSiteCxt))
513
+ {
514
+ CxtStmt newCts(callSiteCxt, outEdge->getDstNode());
515
+ markCxtStmtFlag(newCts, cts);
516
+ }
517
+ }
496
518
  }
497
519
  }
498
520
  }
@@ -517,21 +539,9 @@ void LockAnalysis::handleIntra(const CxtStmt& cts)
517
539
  }
518
540
  }
519
541
 
520
-
521
542
  void LockAnalysis::pushCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
522
543
  {
523
- const FunObjVar* svfcaller = call->getFun();
524
- CallSiteID csId = getTCG()->getCallSiteID(call, callee);
525
-
526
- // /// handle calling context for candidate functions only
527
- // if (isLockCandidateFun(caller) == false)
528
- // return;
529
-
530
- if (tct->inSameCallGraphSCC(getTCG()->getCallGraphNode(svfcaller), getTCG()->getCallGraphNode(callee)) == false)
531
- {
532
- tct->pushCxt(cxt,csId);
533
- DBOUT(DMTA, tct->dumpCxt(cxt));
534
- }
544
+ tct->pushCxt(cxt,call,callee);
535
545
  }
536
546
 
537
547
  bool LockAnalysis::matchCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
@@ -558,6 +568,11 @@ bool LockAnalysis::matchCxt(CallStrCxt& cxt, const CallICFGNode* call, const Fun
558
568
  return true;
559
569
  }
560
570
 
571
+ bool LockAnalysis::isContextSuffix(const CallStrCxt& lhs, const CallStrCxt& call)
572
+ {
573
+ return tct->isContextSuffix(lhs,call);
574
+ }
575
+
561
576
 
562
577
  /*!
563
578
  * Protected by at least one common lock under every context
@@ -615,10 +630,10 @@ bool LockAnalysis::isProtectedByCommonCxtLock(const CxtStmt& cxtStmt1, const Cxt
615
630
  */
616
631
  bool LockAnalysis::isProtectedByCommonCxtLock(const ICFGNode *i1, const ICFGNode *i2)
617
632
  {
618
- if(!hasCxtStmtfromInst(i1) || !hasCxtStmtfromInst(i2))
633
+ if(!hasCxtStmtFromInst(i1) || !hasCxtStmtFromInst(i2))
619
634
  return false;
620
- const CxtStmtSet& ctsset1 = getCxtStmtfromInst(i1);
621
- const CxtStmtSet& ctsset2 = getCxtStmtfromInst(i2);
635
+ const CxtStmtSet& ctsset1 = getCxtStmtsFromInst(i1);
636
+ const CxtStmtSet& ctsset2 = getCxtStmtsFromInst(i2);
622
637
  for (CxtStmtSet::const_iterator cts1 = ctsset1.begin(), ects1 = ctsset1.end(); cts1 != ects1; cts1++)
623
638
  {
624
639
  const CxtStmt& cxtStmt1 = *cts1;
@@ -689,10 +704,10 @@ bool LockAnalysis::isInSameCSSpan(const CxtStmt& cxtStmt1, const CxtStmt& cxtStm
689
704
  */
690
705
  bool LockAnalysis::isInSameCSSpan(const ICFGNode *I1, const ICFGNode *I2) const
691
706
  {
692
- if(!hasCxtStmtfromInst(I1) || !hasCxtStmtfromInst(I2))
707
+ if(!hasCxtStmtFromInst(I1) || !hasCxtStmtFromInst(I2))
693
708
  return false;
694
- const CxtStmtSet& ctsset1 = getCxtStmtfromInst(I1);
695
- const CxtStmtSet& ctsset2 = getCxtStmtfromInst(I2);
709
+ const CxtStmtSet& ctsset1 = getCxtStmtsFromInst(I1);
710
+ const CxtStmtSet& ctsset2 = getCxtStmtsFromInst(I2);
696
711
 
697
712
  for (CxtStmtSet::const_iterator cts1 = ctsset1.begin(), ects1 = ctsset1.end(); cts1 != ects1; cts1++)
698
713
  {
@@ -115,11 +115,8 @@ void MHP::analyzeInterleaving()
115
115
  else if (tct->isCallSite(curInst) && !tct->isExtCall(curInst))
116
116
  {
117
117
  handleCall(cts, rootTid);
118
- CallGraph::FunctionSet callees;
119
- if (!tct->isCandidateFun(getCallee(SVFUtil::cast<CallICFGNode>(curInst), callees)))
120
- handleIntra(cts);
121
118
  }
122
- else if (isRetInstNode(curInst))
119
+ else if (SVFUtil::dyn_cast<FunExitICFGNode>(curInst))
123
120
  {
124
121
  handleRet(cts);
125
122
  }
@@ -167,7 +164,7 @@ void MHP::updateNonCandidateFunInterleaving()
167
164
  if (curNode == entryNode)
168
165
  continue;
169
166
  CxtThreadStmt newCts(cts.getTid(), curCxt, curNode);
170
- threadStmtToTheadInterLeav[newCts] |= threadStmtToTheadInterLeav[cts];
167
+ threadStmtToThreadInterLeav[newCts] |= threadStmtToThreadInterLeav[cts];
171
168
  instToTSMap[curNode].insert(newCts);
172
169
  }
173
170
  }
@@ -312,6 +309,23 @@ void MHP::handleCall(const CxtThreadStmt& cts, NodeID rootTid)
312
309
  addInterleavingThread(newCts, cts);
313
310
  }
314
311
  }
312
+
313
+ /// Propagate to the return site of the call instruction,
314
+ /// only if the callee is a non-candidate function, while for candidate function,
315
+ /// return site should be handled after the callee is handled.
316
+ if (const CallICFGNode *callSite = SVFUtil::cast<CallICFGNode>(call))
317
+ {
318
+ CallGraph::FunctionSet callees;
319
+ if (!tct->isCandidateFun(getCallee(callSite, callees)))
320
+ {
321
+ CxtThreadStmt newCts(cts.getTid(), cts.getContext(), callSite->getRetICFGNode());
322
+ addInterleavingThread(newCts, cts);
323
+ }
324
+ }
325
+ else
326
+ {
327
+ assert(false && "cts.getStmt() is not a CallICFGNode!");
328
+ }
315
329
  }
316
330
 
317
331
  /*!
@@ -329,14 +343,25 @@ void MHP::handleRet(const CxtThreadStmt& cts)
329
343
  cit != ecit; ++cit)
330
344
  {
331
345
  CallStrCxt newCxt = cts.getContext();
332
- if (matchCxt(newCxt, *cit, curFunNode->getFunction()))
346
+ if (matchAndPopCxt(newCxt, *cit, curFunNode->getFunction()))
333
347
  {
334
348
  for(const ICFGEdge* outEdge : cts.getStmt()->getOutEdges())
335
349
  {
336
- if(outEdge->getDstNode()->getFun() == cts.getStmt()->getFun())
350
+ if(outEdge->getDstNode()->getFun() == (*cit)->getFun())
337
351
  {
338
- CxtThreadStmt newCts(cts.getTid(), newCxt, outEdge->getDstNode());
339
- addInterleavingThread(newCts, cts);
352
+ // Iterate over callSite's call string context and use as the successor's context
353
+ if (!hasThreadStmtSet(*cit))
354
+ continue;
355
+ for (const CxtThreadStmt& cxtThreadStmt: getThreadStmtSet(*cit))
356
+ {
357
+ CallStrCxt callSiteCxt = cxtThreadStmt.getContext();
358
+ // If new context is a suffix of the call site context
359
+ if (isContextSuffix(newCxt, callSiteCxt))
360
+ {
361
+ CxtThreadStmt newCts(cts.getTid(), callSiteCxt, outEdge->getDstNode());
362
+ addInterleavingThread(newCts, cts);
363
+ }
364
+ }
340
365
  }
341
366
  }
342
367
  }
@@ -346,14 +371,25 @@ void MHP::handleRet(const CxtThreadStmt& cts)
346
371
  cit != ecit; ++cit)
347
372
  {
348
373
  CallStrCxt newCxt = cts.getContext();
349
- if (matchCxt(newCxt, *cit, curFunNode->getFunction()))
374
+ if (matchAndPopCxt(newCxt, *cit, curFunNode->getFunction()))
350
375
  {
351
376
  for(const ICFGEdge* outEdge : cts.getStmt()->getOutEdges())
352
377
  {
353
- if(outEdge->getDstNode()->getFun() == cts.getStmt()->getFun())
378
+ if(outEdge->getDstNode()->getFun() == (*cit)->getFun())
354
379
  {
355
- CxtThreadStmt newCts(cts.getTid(), newCxt, outEdge->getDstNode());
356
- addInterleavingThread(newCts, cts);
380
+ // Iterate over callSite's call string context and use as the successor's context
381
+ if (!hasThreadStmtSet(*cit))
382
+ continue;
383
+ for (const CxtThreadStmt& cxtThreadStmt: getThreadStmtSet(*cit))
384
+ {
385
+ CallStrCxt callSiteCxt = cxtThreadStmt.getContext();
386
+ // If new context is a suffix of the call site context
387
+ if (isContextSuffix(newCxt, callSiteCxt))
388
+ {
389
+ CxtThreadStmt newCts(cts.getTid(), callSiteCxt, outEdge->getDstNode());
390
+ addInterleavingThread(newCts, cts);
391
+ }
392
+ }
357
393
  }
358
394
  }
359
395
  }
@@ -366,7 +402,6 @@ void MHP::handleRet(const CxtThreadStmt& cts)
366
402
  */
367
403
  void MHP::handleIntra(const CxtThreadStmt& cts)
368
404
  {
369
-
370
405
  for(const ICFGEdge* outEdge : cts.getStmt()->getOutEdges())
371
406
  {
372
407
  if(outEdge->getDstNode()->getFun() == cts.getStmt()->getFun())
@@ -382,24 +417,27 @@ void MHP::handleIntra(const CxtThreadStmt& cts)
382
417
  */
383
418
  void MHP::updateAncestorThreads(NodeID curTid)
384
419
  {
385
- NodeBS tds = tct->getAncestorThread(curTid);
420
+ NodeBS ancestorAndSelfTids = tct->getAncestorThreads(curTid);
386
421
  DBOUT(DMTA, outs() << "##Ancestor thread of " << curTid << " is : ");
387
422
  DBOUT(DMTA, dumpSet(tds));
388
423
  DBOUT(DMTA, outs() << "\n");
389
- tds.set(curTid);
424
+ ancestorAndSelfTids.set(curTid);
390
425
 
391
- for (const unsigned i : tds)
426
+ for (const unsigned tid : ancestorAndSelfTids)
392
427
  {
393
- const CxtThread& ct = tct->getTCTNode(i)->getCxtThread();
428
+ const CxtThread& ct = tct->getTCTNode(tid)->getCxtThread();
394
429
  if (const ICFGNode* forkInst = ct.getThread())
395
430
  {
396
- CallStrCxt forkSiteCxt = tct->getCxtOfCxtThread(ct);
397
431
  for(const ICFGEdge* outEdge : forkInst->getOutEdges())
398
432
  {
433
+ // Ensure dst node is in the same function as forkInst
399
434
  if(outEdge->getDstNode()->getFun() == forkInst->getFun())
400
435
  {
401
- CxtThreadStmt cts(tct->getParentThread(i), forkSiteCxt, outEdge->getDstNode());
402
- addInterleavingThread(cts, curTid);
436
+ for (const auto& forkSiteCxt : tct->getCxtOfCxtThread(ct))
437
+ {
438
+ CxtThreadStmt cts(forkSiteCxt.first, forkSiteCxt.second, outEdge->getDstNode());
439
+ addInterleavingThread(cts, curTid);
440
+ }
403
441
  }
404
442
  }
405
443
  }
@@ -418,9 +456,9 @@ void MHP::updateAncestorThreads(NodeID curTid)
418
456
  */
419
457
  void MHP::updateSiblingThreads(NodeID curTid)
420
458
  {
421
- NodeBS tds = tct->getAncestorThread(curTid);
422
- tds.set(curTid);
423
- for (const unsigned tid : tds)
459
+ NodeBS ancestorAndSelfTids = tct->getAncestorThreads(curTid);
460
+ ancestorAndSelfTids.set(curTid);
461
+ for (const unsigned tid : ancestorAndSelfTids)
424
462
  {
425
463
  NodeBS siblingTds = tct->getSiblingThread(tid);
426
464
  for (const unsigned stid : siblingTds)
@@ -647,7 +685,7 @@ bool MHP::executedByTheSameThread(const ICFGNode* i1, const ICFGNode* i2)
647
685
  */
648
686
  void MHP::printInterleaving()
649
687
  {
650
- for (const auto& pair : threadStmtToTheadInterLeav)
688
+ for (const auto& pair : threadStmtToThreadInterLeav)
651
689
  {
652
690
  outs() << "( t" << pair.first.getTid()
653
691
  << pair.first.getStmt()->toString() << " ) ==> [";
@@ -728,15 +766,16 @@ void ForkJoinAnalysis::analyzeForkJoinPair()
728
766
  clearFlagMap();
729
767
  if (const ICFGNode* forkInst = ct.getThread())
730
768
  {
731
- CallStrCxt forkSiteCxt = tct->getCxtOfCxtThread(ct);
732
- const ICFGNode* exitInst = getExitInstOfParentRoutineFun(rootTid);
733
-
769
+ /// Start from the instruction next to the fork site
734
770
  for(const ICFGEdge* outEdge : forkInst->getOutEdges())
735
771
  {
736
772
  if(outEdge->getDstNode()->getFun() == forkInst->getFun())
737
773
  {
738
- CxtStmt newCts(forkSiteCxt, outEdge->getDstNode());
739
- markCxtStmtFlag(newCts, TDAlive);
774
+ for (const auto& forkSiteCxt : tct->getCxtOfCxtThread(ct))
775
+ {
776
+ CxtStmt newCts(forkSiteCxt.second, outEdge->getDstNode());
777
+ markCxtStmtFlag(newCts, TDAlive);
778
+ }
740
779
  }
741
780
  }
742
781
 
@@ -756,12 +795,25 @@ void ForkJoinAnalysis::analyzeForkJoinPair()
756
795
  {
757
796
  handleJoin(cts, rootTid);
758
797
  }
759
- else if (tct->isCallSite(curInst) && tct->isCandidateFun(getCallee(curInst, callees)))
798
+ else if (tct->isCallSite(curInst) && !tct->isExtCall(curInst))
760
799
  {
761
-
762
- handleCall(cts, rootTid);
800
+ /// Propagate to the return site of the call instruction,
801
+ /// only if the callee is a non-candidate function, while for candidate function,
802
+ /// return site should be handled after the callee is handled.
803
+ const CallICFGNode *callSite = SVFUtil::cast<CallICFGNode>(curInst);
804
+ CallGraph::FunctionSet callees;
805
+ if (!tct->isCandidateFun(getCallee(callSite, callees)))
806
+ {
807
+ // Do not dive into non-candidate functions
808
+ CxtStmt newCts(cts.getContext(), callSite->getRetICFGNode());
809
+ markCxtStmtFlag(newCts, cts);
810
+ }
811
+ else
812
+ {
813
+ handleCall(cts, rootTid);
814
+ }
763
815
  }
764
- else if (isRetInstNode(curInst))
816
+ else if (SVFUtil::dyn_cast<FunExitICFGNode>(curInst))
765
817
  {
766
818
  handleRet(cts);
767
819
  }
@@ -770,12 +822,20 @@ void ForkJoinAnalysis::analyzeForkJoinPair()
770
822
  handleIntra(cts);
771
823
  }
772
824
 
773
- if (curInst == exitInst)
825
+ /// If the current instruction is an exit instruction of the start routine of
826
+ /// a parent context thread, we need to update the join information the parent
827
+ /// context thread.
828
+ for (NodeID parentTid : tct->getParentThreads(rootTid))
774
829
  {
775
- if (getMarkedFlag(cts) != TDAlive)
776
- addToFullJoin(tct->getParentThread(rootTid), rootTid);
777
- else
778
- addToPartial(tct->getParentThread(rootTid), rootTid);
830
+ const CxtThread& parentCxtThread = tct->getTCTNode(parentTid)->getCxtThread();
831
+ const FunObjVar* parentRoutine = tct->getStartRoutineOfCxtThread(parentCxtThread);
832
+ if (curInst == parentRoutine->getExitBB()->back())
833
+ {
834
+ if (getMarkedFlag(cts) != TDAlive)
835
+ addToFullJoin(parentTid, rootTid);
836
+ else
837
+ addToPartial(parentTid, rootTid);
838
+ }
779
839
  }
780
840
  }
781
841
  }
@@ -822,9 +882,12 @@ void ForkJoinAnalysis::handleJoin(const CxtStmt& cts, NodeID rootTid)
822
882
  const ICFGNode* forkSite = tct->getTCTNode(rootTid)->getCxtThread().getThread();
823
883
  const ICFGNode* joinSite = cts.getStmt();
824
884
 
825
- if (isAliasedForkJoin(SVFUtil::cast<CallICFGNode>(forkSite), SVFUtil::cast<CallICFGNode>(joinSite)))
885
+ if (hasJoinLoop(SVFUtil::cast<CallICFGNode>(joinSite)))
826
886
  {
827
- if (hasJoinLoop(SVFUtil::cast<CallICFGNode>(joinSite)))
887
+ if (isAliasedForkJoin(SVFUtil::cast<CallICFGNode>(forkSite),
888
+ SVFUtil::cast<CallICFGNode>(joinSite)) &&
889
+ isSameSCEV(forkSite,joinSite)
890
+ )
828
891
  {
829
892
  LoopBBs& joinLoop = getJoinLoop(SVFUtil::cast<CallICFGNode>(joinSite));
830
893
  std::vector<const SVFBasicBlock *> exitbbs;
@@ -845,18 +908,9 @@ void ForkJoinAnalysis::handleJoin(const CxtStmt& cts, NodeID rootTid)
845
908
  markCxtStmtFlag(cts, TDAlive);
846
909
  }
847
910
  }
911
+ /// for the join site in a loop loop which does not join the current thread
912
+ /// we process the loop exit
848
913
  else
849
- {
850
- markCxtStmtFlag(cts, TDDead);
851
- addDirectlyJoinTID(cts, rootTid);
852
- DBOUT(DMTA, outs() << "\n\t match join site " << call->toString() << "for thread " << rootTid << "\n");
853
- }
854
- }
855
- /// for the join site in a loop loop which does not join the current thread
856
- /// we process the loop exit
857
- else
858
- {
859
- if (hasJoinLoop(SVFUtil::cast<CallICFGNode>(joinSite)))
860
914
  {
861
915
  std::vector<const SVFBasicBlock*> exitbbs;
862
916
  joinSite->getFun()->getExitBlocksOfLoop(joinSite->getBB(), exitbbs);
@@ -870,6 +924,16 @@ void ForkJoinAnalysis::handleJoin(const CxtStmt& cts, NodeID rootTid)
870
924
  }
871
925
  }
872
926
  }
927
+ else
928
+ {
929
+ if (isAliasedForkJoin(SVFUtil::cast<CallICFGNode>(forkSite),
930
+ SVFUtil::cast<CallICFGNode>(joinSite)))
931
+ {
932
+ markCxtStmtFlag(cts, TDDead);
933
+ addDirectlyJoinTID(cts, rootTid);
934
+ DBOUT(DMTA, outs() << "\n\t match join site " << call->toString() << "for thread " << rootTid << "\n");
935
+ }
936
+ }
873
937
  }
874
938
  handleIntra(cts);
875
939
  }
@@ -916,14 +980,25 @@ void ForkJoinAnalysis::handleRet(const CxtStmt& cts)
916
980
  {
917
981
  CallStrCxt newCxt = curCxt;
918
982
  const ICFGNode* curNode = (*cit);
919
- if (matchCxt(newCxt, SVFUtil::cast<CallICFGNode>(curNode), curFunNode->getFunction()))
983
+ if (matchAndPopCxt(newCxt, SVFUtil::cast<CallICFGNode>(curNode), curFunNode->getFunction()))
920
984
  {
921
985
  for(const ICFGEdge* outEdge : curNode->getOutEdges())
922
986
  {
923
987
  if(outEdge->getDstNode()->getFun() == curNode->getFun())
924
988
  {
925
- CxtStmt newCts(newCxt, outEdge->getDstNode());
926
- markCxtStmtFlag(newCts, cts);
989
+ // Iterate over callSite's call string context and use as the successor's context
990
+ if (!hasCxtStmtsFromInst(*cit))
991
+ continue;
992
+ for (const CxtStmt& cxtStmt: getCxtStmtsFromInst(*cit))
993
+ {
994
+ CallStrCxt callSiteCxt = cxtStmt.getContext();
995
+ // If new context is a suffix of the call site context
996
+ if (isContextSuffix(newCxt, callSiteCxt))
997
+ {
998
+ CxtStmt newCts(callSiteCxt, outEdge->getDstNode());
999
+ markCxtStmtFlag(newCts, cts);
1000
+ }
1001
+ }
927
1002
  }
928
1003
  }
929
1004
  }
@@ -935,14 +1010,25 @@ void ForkJoinAnalysis::handleRet(const CxtStmt& cts)
935
1010
  CallStrCxt newCxt = curCxt;
936
1011
  const ICFGNode* curNode = (*cit);
937
1012
 
938
- if (matchCxt(newCxt, SVFUtil::cast<CallICFGNode>(curNode), curFunNode->getFunction()))
1013
+ if (matchAndPopCxt(newCxt, SVFUtil::cast<CallICFGNode>(curNode), curFunNode->getFunction()))
939
1014
  {
940
1015
  for(const ICFGEdge* outEdge : curNode->getOutEdges())
941
1016
  {
942
1017
  if(outEdge->getDstNode()->getFun() == curNode->getFun())
943
1018
  {
944
- CxtStmt newCts(newCxt, outEdge->getDstNode());
945
- markCxtStmtFlag(newCts, cts);
1019
+ // Iterate over callSite's call string context and use as the successor's context
1020
+ if (!hasCxtStmtsFromInst(*cit))
1021
+ continue;
1022
+ for (const CxtStmt& cxtStmt: getCxtStmtsFromInst(*cit))
1023
+ {
1024
+ CallStrCxt callSiteCxt = cxtStmt.getContext();
1025
+ // If new context is a suffix of the call site context
1026
+ if (isContextSuffix(newCxt, callSiteCxt))
1027
+ {
1028
+ CxtStmt newCts(callSiteCxt, outEdge->getDstNode());
1029
+ markCxtStmtFlag(newCts, cts);
1030
+ }
1031
+ }
946
1032
  }
947
1033
  }
948
1034
  }
@@ -49,8 +49,7 @@ MTA::~MTA()
49
49
  {
50
50
  if (tcg)
51
51
  delete tcg;
52
- //if (tct)
53
- // delete tct;
52
+
54
53
  delete mhp;
55
54
  delete lsa;
56
55
  }
@@ -60,33 +59,12 @@ MTA::~MTA()
60
59
  */
61
60
  bool MTA::runOnModule(SVFIR* pag)
62
61
  {
63
- mhp = computeMHP();
64
- lsa = computeLocksets(mhp->getTCT());
65
-
66
- if(Options::RaceCheck())
67
- detect();
68
-
69
- return false;
70
- }
71
-
72
- /*!
73
- * Compute lock sets
74
- */
75
- LockAnalysis* MTA::computeLocksets(TCT* tct)
76
- {
77
- LockAnalysis* lsa = new LockAnalysis(tct);
78
- lsa->analyze();
79
- return lsa;
80
- }
81
-
82
- MHP* MTA::computeMHP()
83
- {
84
-
85
62
  DBOUT(DGENERAL, outs() << pasMsg("MTA analysis\n"));
86
63
  DBOUT(DMTA, outs() << pasMsg("MTA analysis\n"));
87
- SVFIR* pag = PAG::getPAG();
64
+
88
65
  PointerAnalysis* pta = AndersenWaveDiff::createAndersenWaveDiff(pag);
89
66
  pta->getCallGraph()->dump("ptacg");
67
+ pag->getICFG()->updateCallGraph(pta->getCallGraph());
90
68
 
91
69
  DBOUT(DGENERAL, outs() << pasMsg("Build TCT\n"));
92
70
  DBOUT(DMTA, outs() << pasMsg("Build TCT\n"));
@@ -104,11 +82,32 @@ MHP* MTA::computeMHP()
104
82
 
105
83
  tcg->dump("tcg");
106
84
 
85
+ mhp = computeMHP(tct.get());
86
+ lsa = computeLocksets(tct.get());
87
+
88
+ if(Options::RaceCheck())
89
+ detect();
90
+
91
+ return false;
92
+ }
93
+
94
+ /*!
95
+ * Compute lock sets
96
+ */
97
+ LockAnalysis* MTA::computeLocksets(TCT* tct)
98
+ {
99
+ LockAnalysis* lsa = new LockAnalysis(tct);
100
+ lsa->analyze();
101
+ return lsa;
102
+ }
103
+
104
+ MHP* MTA::computeMHP(TCT* tct)
105
+ {
107
106
  DBOUT(DGENERAL, outs() << pasMsg("MHP analysis\n"));
108
107
  DBOUT(DMTA, outs() << pasMsg("MHP analysis\n"));
109
108
 
110
109
  DOTIMESTAT(double mhpStart = stat->getClk());
111
- MHP* mhp = new MHP(tct.get());
110
+ MHP* mhp = new MHP(tct);
112
111
  mhp->analyze();
113
112
  DOTIMESTAT(double mhpEnd = stat->getClk());
114
113
  DOTIMESTAT(stat->MHPTime += (mhpEnd - mhpStart) / TIMEINTERVAL);
@@ -156,7 +156,7 @@ void TCT::markRelProcs()
156
156
  }
157
157
 
158
158
  /*!
159
- *
159
+ * Add relevant procedures that are backward reachable from svffun on Thread Call Graph
160
160
  */
161
161
  void TCT::markRelProcs(const FunObjVar* svffun)
162
162
  {
@@ -182,7 +182,7 @@ void TCT::markRelProcs(const FunObjVar* svffun)
182
182
  }
183
183
 
184
184
  /*!
185
- * Get Main function
185
+ * Get entry function, i.e., functions without callers, e.g., main function
186
186
  */
187
187
  void TCT::collectEntryFunInCallGraph()
188
188
  {
@@ -249,7 +249,10 @@ void TCT::handleCallRelation(CxtThreadProc& ctp, const CallGraphEdge* cgEdge, co
249
249
  CallStrCxt cxt(ctp.getContext());
250
250
  CallStrCxt oldCxt = cxt;
251
251
  const CallICFGNode* callNode = cs;
252
- pushCxt(cxt,callNode,callee);
252
+
253
+ /// handle calling context for candidate functions only
254
+ if(isCandidateFun(callNode->getFun()) == true)
255
+ pushCxt(cxt,callNode,callee);
253
256
 
254
257
  if(cgEdge->getEdgeKind() == CallGraphEdge::CallRetEdge)
255
258
  {
@@ -264,7 +267,7 @@ void TCT::handleCallRelation(CxtThreadProc& ctp, const CallGraphEdge* cgEdge, co
264
267
  else if(cgEdge->getEdgeKind() == CallGraphEdge::TDForkEdge)
265
268
  {
266
269
  /// Create spawnee TCT node
267
- TCTNode* spawneeNode = getOrCreateTCTNode(cxt,callNode, oldCxt, callee);
270
+ TCTNode* spawneeNode = getOrCreateTCTNode(cxt,callNode, ctp, callee);
268
271
  CxtThreadProc newctp(spawneeNode->getId(),cxt,callee);
269
272
 
270
273
  if(pushToCTPWorkList(newctp))
@@ -398,7 +401,8 @@ void TCT::build()
398
401
  if (!isCandidateFun(*it))
399
402
  continue;
400
403
  CallStrCxt cxt;
401
- TCTNode* mainTCTNode = getOrCreateTCTNode(cxt, nullptr, cxt, *it);
404
+ CxtThreadProc dummyCtp(-1, cxt, nullptr);
405
+ TCTNode* mainTCTNode = getOrCreateTCTNode(cxt, nullptr, dummyCtp, *it);
402
406
  CxtThreadProc t(mainTCTNode->getId(), cxt, *it);
403
407
  pushToCTPWorkList(t);
404
408
  }
@@ -440,21 +444,20 @@ void TCT::build()
440
444
  }
441
445
 
442
446
  /*!
443
- * Push calling context
447
+ * Push calling context, with k limiting
444
448
  */
445
449
  void TCT::pushCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
446
450
  {
447
-
448
451
  const FunObjVar* caller = call->getFun();
449
452
  CallSiteID csId = tcg->getCallSiteID(call, callee);
450
453
 
451
- /// handle calling context for candidate functions only
452
- if(isCandidateFun(caller) == false)
453
- return;
454
-
455
454
  if(inSameCallGraphSCC(tcg->getCallGraphNode(caller),tcg->getCallGraphNode(callee))==false)
456
455
  {
457
- pushCxt(cxt,csId);
456
+ cxt.push_back(csId);
457
+ if (cxt.size() > Options::MaxContextLen())
458
+ cxt.erase(cxt.begin());
459
+ if (cxt.size() > MaxCxtSize)
460
+ MaxCxtSize = cxt.size();
458
461
  DBOUT(DMTA,dumpCxt(cxt));
459
462
  }
460
463
  }
@@ -463,9 +466,8 @@ void TCT::pushCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* ca
463
466
  /*!
464
467
  * Match calling context
465
468
  */
466
- bool TCT::matchCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
469
+ bool TCT::matchAndPopCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee)
467
470
  {
468
-
469
471
  const FunObjVar* caller = call->getFun();
470
472
  CallSiteID csId = tcg->getCallSiteID(call, callee);
471
473
 
@@ -489,6 +491,25 @@ bool TCT::matchCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* c
489
491
  return true;
490
492
  }
491
493
 
494
+ /*!
495
+ * If lhs is a suffix of rhs, including equal
496
+ */
497
+ bool TCT::isContextSuffix(const CallStrCxt& lhs, const CallStrCxt& call)
498
+ {
499
+ if (lhs.size() > call.size())
500
+ return false;
501
+ bool isSuffix = true;
502
+ for (size_t i = 0; i < lhs.size(); ++i)
503
+ {
504
+ if (lhs[lhs.size() - 1 - i] != call[call.size() - 1 - i])
505
+ {
506
+ isSuffix = false;
507
+ break;
508
+ }
509
+ }
510
+ return isSuffix;
511
+ }
512
+
492
513
 
493
514
  /*!
494
515
  * Dump calling context information
@@ -513,8 +534,7 @@ void TCT::dumpCxt(CallStrCxt& cxt)
513
534
  */
514
535
  void TCT::dump(const std::string& filename)
515
536
  {
516
- if (Options::TCTDotGraph())
517
- GraphPrinter::WriteGraphToFile(outs(), filename, this);
537
+ GraphPrinter::WriteGraphToFile(outs(), filename, this);
518
538
  }
519
539
 
520
540
  /*!