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