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 +1 -1
- package/svf/include/MTA/LockAnalysis.h +12 -9
- package/svf/include/MTA/MHP.h +56 -20
- package/svf/include/MTA/MTA.h +1 -1
- package/svf/include/MTA/TCT.h +47 -46
- package/svf/lib/MTA/LockAnalysis.cpp +41 -26
- package/svf/lib/MTA/MHP.cpp +144 -58
- package/svf/lib/MTA/MTA.cpp +25 -26
- package/svf/lib/MTA/TCT.cpp +36 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svf-tools",
|
|
3
|
-
"version": "1.0.
|
|
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*,
|
|
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
|
|
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&
|
|
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(!
|
|
272
|
+
if(!hasCxtStmtFromInst(I))
|
|
275
273
|
return false;
|
|
276
|
-
const LockSpan ctsset =
|
|
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(!
|
|
287
|
+
if(!hasCxtStmtFromInst(I))
|
|
290
288
|
return false;
|
|
291
|
-
const LockSpan ctsset =
|
|
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)
|
package/svf/include/MTA/MHP.h
CHANGED
|
@@ -96,11 +96,11 @@ public:
|
|
|
96
96
|
//@{
|
|
97
97
|
inline const NodeBS& getInterleavingThreads(const CxtThreadStmt& cts)
|
|
98
98
|
{
|
|
99
|
-
return
|
|
99
|
+
return threadStmtToThreadInterLeav[cts];
|
|
100
100
|
}
|
|
101
101
|
inline bool hasInterleavingThreads(const CxtThreadStmt& cts) const
|
|
102
102
|
{
|
|
103
|
-
return
|
|
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(
|
|
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 =
|
|
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(
|
|
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
|
|
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->
|
|
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
|
|
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())
|
|
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
|
|
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->
|
|
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
|
package/svf/include/MTA/MTA.h
CHANGED
|
@@ -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
|
package/svf/include/MTA/TCT.h
CHANGED
|
@@ -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
|
|
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
|
|
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::
|
|
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
|
|
314
|
-
inline
|
|
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()
|
|
318
|
-
|
|
319
|
-
const TCTEdge* edge
|
|
320
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
354
|
-
|
|
355
|
-
|
|
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
|
|
363
|
-
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
|
-
|
|
366
|
-
assert(it!=
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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() ==
|
|
475
|
+
if(outEdge->getDstNode()->getFun() == inst->getFun())
|
|
476
476
|
{
|
|
477
|
-
|
|
478
|
-
|
|
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() ==
|
|
503
|
+
if(outEdge->getDstNode()->getFun() == inst->getFun())
|
|
493
504
|
{
|
|
494
|
-
|
|
495
|
-
|
|
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
|
-
|
|
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(!
|
|
633
|
+
if(!hasCxtStmtFromInst(i1) || !hasCxtStmtFromInst(i2))
|
|
619
634
|
return false;
|
|
620
|
-
const CxtStmtSet& ctsset1 =
|
|
621
|
-
const CxtStmtSet& ctsset2 =
|
|
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(!
|
|
707
|
+
if(!hasCxtStmtFromInst(I1) || !hasCxtStmtFromInst(I2))
|
|
693
708
|
return false;
|
|
694
|
-
const CxtStmtSet& ctsset1 =
|
|
695
|
-
const CxtStmtSet& ctsset2 =
|
|
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
|
{
|
package/svf/lib/MTA/MHP.cpp
CHANGED
|
@@ -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 (
|
|
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
|
-
|
|
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 (
|
|
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() ==
|
|
350
|
+
if(outEdge->getDstNode()->getFun() == (*cit)->getFun())
|
|
337
351
|
{
|
|
338
|
-
|
|
339
|
-
|
|
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 (
|
|
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() ==
|
|
378
|
+
if(outEdge->getDstNode()->getFun() == (*cit)->getFun())
|
|
354
379
|
{
|
|
355
|
-
|
|
356
|
-
|
|
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
|
|
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
|
-
|
|
424
|
+
ancestorAndSelfTids.set(curTid);
|
|
390
425
|
|
|
391
|
-
for (const unsigned
|
|
426
|
+
for (const unsigned tid : ancestorAndSelfTids)
|
|
392
427
|
{
|
|
393
|
-
const CxtThread& ct = tct->getTCTNode(
|
|
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
|
-
|
|
402
|
-
|
|
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
|
|
422
|
-
|
|
423
|
-
for (const unsigned tid :
|
|
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 :
|
|
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
|
-
|
|
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
|
-
|
|
739
|
-
|
|
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->
|
|
798
|
+
else if (tct->isCallSite(curInst) && !tct->isExtCall(curInst))
|
|
760
799
|
{
|
|
761
|
-
|
|
762
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
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 (
|
|
885
|
+
if (hasJoinLoop(SVFUtil::cast<CallICFGNode>(joinSite)))
|
|
826
886
|
{
|
|
827
|
-
if (
|
|
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 (
|
|
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
|
-
|
|
926
|
-
|
|
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 (
|
|
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
|
-
|
|
945
|
-
|
|
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
|
}
|
package/svf/lib/MTA/MTA.cpp
CHANGED
|
@@ -49,8 +49,7 @@ MTA::~MTA()
|
|
|
49
49
|
{
|
|
50
50
|
if (tcg)
|
|
51
51
|
delete tcg;
|
|
52
|
-
|
|
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
|
-
|
|
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
|
|
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);
|
package/svf/lib/MTA/TCT.cpp
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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::
|
|
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
|
-
|
|
517
|
-
GraphPrinter::WriteGraphToFile(outs(), filename, this);
|
|
537
|
+
GraphPrinter::WriteGraphToFile(outs(), filename, this);
|
|
518
538
|
}
|
|
519
539
|
|
|
520
540
|
/*!
|