svf-lib 1.0.2676 → 1.0.2677
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/bin/svf-ex +0 -0
- package/SVF-linux-aarch64/include/Graphs/CallGraph.h +18 -0
- package/SVF-linux-aarch64/include/Graphs/DOTGraphTraits.h +33 -20
- package/SVF-linux-aarch64/include/Graphs/GraphPrinter.h +1 -1
- package/SVF-linux-aarch64/include/Graphs/GraphWriter.h +6 -7
- package/SVF-linux-aarch64/include/Graphs/ICFG.h +40 -0
- package/SVF-linux-aarch64/include/Graphs/SVFG.h +8 -0
- package/SVF-linux-aarch64/include/Graphs/SlicedGraphs.h +1801 -0
- package/SVF-linux-aarch64/include/Graphs/ThreadCallGraph.h +13 -4
- package/SVF-linux-aarch64/include/MSSA/MemRegion.h +17 -0
- package/SVF-linux-aarch64/include/MSSA/MemSSA.h +7 -5
- package/SVF-linux-aarch64/include/MSSA/SVFGBuilder.h +6 -0
- package/SVF-linux-aarch64/include/MTA/FSMPTA.h +91 -0
- package/SVF-linux-aarch64/include/MTA/LockAnalysis.h +40 -25
- package/SVF-linux-aarch64/include/MTA/MHP.h +54 -21
- package/SVF-linux-aarch64/include/MTA/MTA.h +186 -3
- package/SVF-linux-aarch64/include/MTA/MTASVFGBuilder.h +176 -0
- package/SVF-linux-aarch64/include/MTA/MTASlicer.h +275 -0
- package/SVF-linux-aarch64/include/MTA/MTAStat.h +0 -2
- package/SVF-linux-aarch64/include/MTA/TCT.h +70 -29
- package/SVF-linux-aarch64/include/Util/CommandLine.h +5 -0
- package/SVF-linux-aarch64/include/Util/CxtStmt.h +29 -19
- package/SVF-linux-aarch64/include/Util/Options.h +12 -6
- package/SVF-linux-aarch64/include/Util/ThreadAPI.h +12 -0
- package/SVF-linux-aarch64/lib/cmake/SVF/SVFTargets.cmake +1 -1
- package/SVF-linux-aarch64/lib/libSvfCore.so.3.4 +0 -0
- package/package.json +1 -1
|
@@ -26,25 +26,58 @@
|
|
|
26
26
|
* Created on: May 14, 2014
|
|
27
27
|
* Author: Yulei Sui, Peng Di
|
|
28
28
|
*
|
|
29
|
-
* The
|
|
29
|
+
* The base data race detector is based on
|
|
30
30
|
* Yulei Sui, Peng Di, and Jingling Xue. "Sparse Flow-Sensitive Pointer Analysis for Multithreaded Programs".
|
|
31
31
|
* 2016 International Symposium on Code Generation and Optimization (CGO'16)
|
|
32
|
+
*
|
|
33
|
+
* This file also declares SlicedMTA, the multi-stage on-demand program slicing
|
|
34
|
+
* pipeline (MSli) introduced in "Multi-Stage On-Demand Program Slicing for
|
|
35
|
+
* Modular Analysis of Multi-Threaded Programs" (ISSTA 2026).
|
|
32
36
|
*/
|
|
33
37
|
|
|
34
38
|
#ifndef MTA_H_
|
|
35
39
|
#define MTA_H_
|
|
36
40
|
|
|
41
|
+
#include <set>
|
|
42
|
+
#include <string>
|
|
43
|
+
#include <vector>
|
|
44
|
+
#include <functional>
|
|
45
|
+
#include <memory>
|
|
46
|
+
#include <utility>
|
|
47
|
+
#include "SVFIR/SVFIR.h"
|
|
48
|
+
#include "SVFIR/SVFValue.h"
|
|
49
|
+
#include "SVFIR/SVFStatements.h"
|
|
50
|
+
#include "SVFIR/SVFVariables.h"
|
|
51
|
+
#include "MemoryModel/PointsTo.h"
|
|
52
|
+
#include "MTA/MHP.h"
|
|
53
|
+
#include "MTA/LockAnalysis.h"
|
|
54
|
+
#include "WPA/Andersen.h"
|
|
55
|
+
#include "Graphs/CallGraph.h"
|
|
56
|
+
|
|
37
57
|
namespace SVF
|
|
38
58
|
{
|
|
39
59
|
|
|
40
60
|
class PointerAnalysis;
|
|
41
61
|
class AndersenWaveDiff;
|
|
62
|
+
class AndersenBase;
|
|
42
63
|
class ThreadCallGraph;
|
|
64
|
+
class CallGraph;
|
|
43
65
|
class MTAStat;
|
|
44
66
|
class TCT;
|
|
45
67
|
class MHP;
|
|
46
68
|
class LockAnalysis;
|
|
69
|
+
class SVFStmt;
|
|
47
70
|
class SVFIR;
|
|
71
|
+
class ICFGNode;
|
|
72
|
+
// Forward declarations for the SlicedMTA slicing pipeline (see SlicedMTA impl).
|
|
73
|
+
class MTASVFGBuilder;
|
|
74
|
+
class SVFG;
|
|
75
|
+
class FlowSensitive;
|
|
76
|
+
class SlicedSVFGView;
|
|
77
|
+
class MultiStageSlicer;
|
|
78
|
+
class SingleSlicer;
|
|
79
|
+
class SlicedSVFIRView;
|
|
80
|
+
class SlicedTCT;
|
|
48
81
|
|
|
49
82
|
/*!
|
|
50
83
|
* Base data race detector
|
|
@@ -66,8 +99,8 @@ public:
|
|
|
66
99
|
virtual MHP* computeMHP(TCT* tct);
|
|
67
100
|
/// Compute locksets
|
|
68
101
|
virtual LockAnalysis* computeLocksets(TCT* tct);
|
|
69
|
-
///
|
|
70
|
-
virtual void
|
|
102
|
+
/// Run the shared detector and print a race report
|
|
103
|
+
virtual void reportRaces();
|
|
71
104
|
|
|
72
105
|
// Not implemented for now
|
|
73
106
|
// void dump(Module &module, MHP *mhp, LockAnalysis *lsa);
|
|
@@ -81,7 +114,53 @@ public:
|
|
|
81
114
|
{
|
|
82
115
|
return lsa;
|
|
83
116
|
}
|
|
117
|
+
|
|
118
|
+
/// A race pair: two statements that may race.
|
|
119
|
+
struct RacePair
|
|
120
|
+
{
|
|
121
|
+
const SVFStmt* stmt1;
|
|
122
|
+
const SVFStmt* stmt2;
|
|
123
|
+
RacePair(const SVFStmt* s1, const SVFStmt* s2) : stmt1(s1), stmt2(s2) {}
|
|
124
|
+
bool operator<(const RacePair& other) const
|
|
125
|
+
{
|
|
126
|
+
if (stmt1 != other.stmt1) return stmt1 < other.stmt1;
|
|
127
|
+
return stmt2 < other.stmt2;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/// Shared equivalence-class race detector (used by both MTA::reportRaces and
|
|
132
|
+
/// the SlicedMTA pipeline). Returns the racy statements and fills outRacePairs.
|
|
133
|
+
static std::set<const SVFStmt*> detectRace(
|
|
134
|
+
SVFIR* svfIr, AndersenBase* pta, MHP* mhp, LockAnalysis* lockAnalysis,
|
|
135
|
+
CallGraph* callGraph, std::set<RacePair>& outRacePairs);
|
|
136
|
+
|
|
137
|
+
/// Escape/points-to helpers for the shared detector.
|
|
138
|
+
static PointsTo getGlobalObjectVariables(SVFIR* svfIr);
|
|
139
|
+
static PointsTo getPointsToClosure(AndersenBase* pta, const PointsTo& pts);
|
|
140
|
+
|
|
141
|
+
/// Whether the program has any thread (fork-target) function reachable via a
|
|
142
|
+
/// fork edge.
|
|
143
|
+
static bool hasThreadFunctions(CallGraph* callGraph);
|
|
144
|
+
|
|
84
145
|
private:
|
|
146
|
+
/// One occurrence of a memory access under one thread instance.
|
|
147
|
+
struct RaceOccurrence
|
|
148
|
+
{
|
|
149
|
+
const SVFStmt* stmt;
|
|
150
|
+
const ICFGNode* node;
|
|
151
|
+
bool isStore;
|
|
152
|
+
NodeID tid;
|
|
153
|
+
NodeBS interleav;
|
|
154
|
+
bool locked;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/// Helpers for the equivalence-class race detector.
|
|
158
|
+
//@{
|
|
159
|
+
static bool occurrencesRace(MHP* mhp, const RaceOccurrence& first, const RaceOccurrence& second);
|
|
160
|
+
static void commitRacePair(std::set<RacePair>& out,
|
|
161
|
+
const RaceOccurrence& first, const RaceOccurrence& second);
|
|
162
|
+
//@}
|
|
163
|
+
|
|
85
164
|
ThreadCallGraph* tcg;
|
|
86
165
|
std::unique_ptr<TCT> tct;
|
|
87
166
|
std::unique_ptr<MTAStat> stat;
|
|
@@ -89,6 +168,110 @@ private:
|
|
|
89
168
|
LockAnalysis* lsa;
|
|
90
169
|
};
|
|
91
170
|
|
|
171
|
+
/*!
|
|
172
|
+
* Multi-stage on-demand slicing race detection pipeline (MSli).
|
|
173
|
+
*
|
|
174
|
+
* runOnModule drives five stages on a pre-built SVFIR:
|
|
175
|
+
* 1. (caller) build SVFIR + resolve indirect calls into the PAG
|
|
176
|
+
* 2. pre-analysis: Andersen, TCT, MHP, lock, candidate race pairs, VFG_pre
|
|
177
|
+
* 3. MTA slicing: slice the thread-aware graph, build the sliced MHP/lock
|
|
178
|
+
* 4. PTA slicing + main flow-sensitive FSAM (FSMPTA) on the slice
|
|
179
|
+
* 5. final race detection on the sliced graph using FSAM points-to
|
|
180
|
+
*
|
|
181
|
+
* It operates entirely on the SVFIR (LLVM-free). The single LLVM-dependent step --
|
|
182
|
+
* materialising resolved indirect calls into the PAG -- is injected by the caller
|
|
183
|
+
* as a callback (see runOnModule).
|
|
184
|
+
*
|
|
185
|
+
* Behaviour is controlled by Options (MTFlowSensitive, EnableSlicing,
|
|
186
|
+
* SlicingSingle, SlicedDumpDot).
|
|
187
|
+
*/
|
|
188
|
+
class SlicedMTA
|
|
189
|
+
{
|
|
190
|
+
public:
|
|
191
|
+
/// The one LLVM-dependent step of the pipeline: resolve the indirect-call
|
|
192
|
+
/// edges discovered by Andersen into PAG copy/call edges. The caller (the
|
|
193
|
+
/// LLVM-aware tool) supplies it via SVFIRBuilder::updateCallGraph.
|
|
194
|
+
using ResolveIndirectCalls = std::function<void(CallGraph*)>;
|
|
195
|
+
|
|
196
|
+
/// The shared race detector lives in MTA; reuse its race-pair type.
|
|
197
|
+
using RacePair = MTA::RacePair;
|
|
198
|
+
|
|
199
|
+
// Out-of-line (defined where the member types are complete) so callers that
|
|
200
|
+
// only see the forward-declared unique_ptr member types need not be complete.
|
|
201
|
+
SlicedMTA();
|
|
202
|
+
~SlicedMTA();
|
|
203
|
+
|
|
204
|
+
SlicedMTA(const SlicedMTA&) = delete;
|
|
205
|
+
SlicedMTA& operator=(const SlicedMTA&) = delete;
|
|
206
|
+
|
|
207
|
+
/// Run the slicing pipeline on a pre-built SVFIR.
|
|
208
|
+
void runOnModule(SVFIR* pag, const ResolveIndirectCalls& resolveIndirectCalls);
|
|
209
|
+
|
|
210
|
+
private:
|
|
211
|
+
// --- pipeline stages ---
|
|
212
|
+
bool runPreAnalysis(const ResolveIndirectCalls& resolveIndirectCalls);
|
|
213
|
+
bool runMTASlicingAndAnalysis();
|
|
214
|
+
bool runPTASlicingAndAnalysis();
|
|
215
|
+
bool runFinalRaceDetection();
|
|
216
|
+
void buildVFGPre();
|
|
217
|
+
|
|
218
|
+
/// No-slice A/B baseline: run the FSAM detection on the whole program (no
|
|
219
|
+
/// slicing), so its time and race set can be compared against the sliced run.
|
|
220
|
+
void runWholeProgramDetection();
|
|
221
|
+
|
|
222
|
+
/// Main pointer-analysis instance feeding final race detection (the
|
|
223
|
+
/// flow-sensitive FSAM, a BVDataPTAImpl queried polymorphically).
|
|
224
|
+
BVDataPTAImpl* getMainPTA() const;
|
|
225
|
+
|
|
226
|
+
/// Union of both statements of every candidate race pair (the slice targets).
|
|
227
|
+
std::set<const SVFStmt*> getVulnerableStmts() const;
|
|
228
|
+
|
|
229
|
+
// --- race detection ---
|
|
230
|
+
/// Re-check the candidate race pairs on the sliced graph using FSAM points-to.
|
|
231
|
+
std::set<RacePair> detectRacePairsOnSlicedGraph(
|
|
232
|
+
BVDataPTAImpl* slicedPTA, MHP* slicedMHP, LockAnalysis* slicedLockAnalysis);
|
|
233
|
+
|
|
234
|
+
// Lock analysis over the WHOLE ICFG (real control flow, no bridging) for the
|
|
235
|
+
// final detection's lock signature. The sliced lock analysis walks bridged
|
|
236
|
+
// edges, which fabricate lock-carrying paths the whole program lacks (a
|
|
237
|
+
// query-preservation break); lock-span is control-flow-sensitive, so it must
|
|
238
|
+
// see real edges. Built lazily, cheap (no FSAM/MHP) next to the slicing win.
|
|
239
|
+
LockAnalysis* buildFullLockAnalysis();
|
|
240
|
+
|
|
241
|
+
// --- pipeline state (owned unless noted) ---
|
|
242
|
+
SVFIR* svfIr = nullptr;
|
|
243
|
+
// Main-phase context depth, set by runOnModule; the pre-analysis uses it
|
|
244
|
+
// to reconcile context-truncation-merged thread instances.
|
|
245
|
+
u32_t mainCxtDepth = 2;
|
|
246
|
+
std::unique_ptr<TCT> tct;
|
|
247
|
+
std::unique_ptr<MHP> mhp;
|
|
248
|
+
std::unique_ptr<LockAnalysis> lockAnalysis;
|
|
249
|
+
// Inclusion-based Andersen's pre-analysis (a shared singleton, not owned
|
|
250
|
+
// here -- released once in the destructor). Feeds the TCT / MHP / lock /
|
|
251
|
+
// race pre-analysis, the thread-aware VFG_pre, and the main FSMPTA.
|
|
252
|
+
AndersenWaveDiff* preAnder = nullptr;
|
|
253
|
+
std::unique_ptr<MTASVFGBuilder> vfgPreBuilder; // owns vfgPre
|
|
254
|
+
SVFG* vfgPre = nullptr;
|
|
255
|
+
std::unique_ptr<MultiStageSlicer> multiStageSlicer;
|
|
256
|
+
std::unique_ptr<SingleSlicer> singleSlicer;
|
|
257
|
+
// -mta-slicing-single: the one unified slice, computed in MTA slicing and reused
|
|
258
|
+
// (not recomputed) for PTA slicing so both stages share V_Single.
|
|
259
|
+
std::set<const ICFGNode*> singleSlicedNodes;
|
|
260
|
+
std::unique_ptr<SlicedSVFIRView> mtaSlicedView;
|
|
261
|
+
std::unique_ptr<SlicedSVFIRView> ptaSlicedView;
|
|
262
|
+
std::unique_ptr<SlicedSVFGView> slicedSVFGView;
|
|
263
|
+
std::unique_ptr<FlowSensitive> mtaFSMPTA;
|
|
264
|
+
std::unique_ptr<SlicedTCT> slicedTCT;
|
|
265
|
+
std::unique_ptr<MHP> slicedMhp;
|
|
266
|
+
std::unique_ptr<LockAnalysis> slicedLockAnalysis;
|
|
267
|
+
// Whole-ICFG lock analysis for the final detection (see buildFullLockAnalysis).
|
|
268
|
+
std::unique_ptr<SlicedSVFIRView> fullLockView;
|
|
269
|
+
std::unique_ptr<SlicedTCT> fullLockTCT;
|
|
270
|
+
std::unique_ptr<LockAnalysis> fullLockAnalysis;
|
|
271
|
+
bool hasThreadFunctions = false;
|
|
272
|
+
std::set<RacePair> racePairs;
|
|
273
|
+
};
|
|
274
|
+
|
|
92
275
|
} // End namespace SVF
|
|
93
276
|
|
|
94
277
|
#endif /* MTA_H_ */
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
//===- MTASVFGBuilder.h -- Thread-aware SVFG builder for FSAM -----------===//
|
|
2
|
+
//
|
|
3
|
+
// SVF: Static Value-Flow Analysis
|
|
4
|
+
//
|
|
5
|
+
// Copyright (C) <2013-> <Yulei Sui>
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
// This program is free software: you can redistribute it and/or modify
|
|
9
|
+
// it under the terms of the GNU Affero General Public License as published by
|
|
10
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
11
|
+
// (at your option) any later version.
|
|
12
|
+
|
|
13
|
+
// This program is distributed in the hope that it will be useful,
|
|
14
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
// GNU Affero General Public License for more details.
|
|
17
|
+
|
|
18
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
19
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
20
|
+
//
|
|
21
|
+
//===----------------------------------------------------------------------===//
|
|
22
|
+
|
|
23
|
+
/*
|
|
24
|
+
* MTASVFGBuilder.h
|
|
25
|
+
*
|
|
26
|
+
* Author: Jiawei Yang
|
|
27
|
+
*
|
|
28
|
+
* Builds a *thread-aware* Sparse Value-Flow Graph (SVFG) for the FSAM
|
|
29
|
+
* flow-sensitive multithreaded pointer analysis (Sui, Di, Xue, CGO'16).
|
|
30
|
+
*
|
|
31
|
+
* On top of the stock thread-oblivious SVFG, it adds inter-thread (interference)
|
|
32
|
+
* indirect value-flow edges between store/load and store/store statements that
|
|
33
|
+
* (1) may-happen-in-parallel (MHP), and
|
|
34
|
+
* (2) may-alias on the address-taken object, and
|
|
35
|
+
* (3) are not excluded by a common lock (non-interference lock-pair pruning).
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
#ifndef INCLUDE_MTA_MTASVFGBUILDER_H_
|
|
39
|
+
#define INCLUDE_MTA_MTASVFGBUILDER_H_
|
|
40
|
+
|
|
41
|
+
#include "MSSA/SVFGBuilder.h"
|
|
42
|
+
#include "Graphs/SVFG.h"
|
|
43
|
+
#include "Graphs/SVFGEdge.h"
|
|
44
|
+
#include "MTA/MHP.h"
|
|
45
|
+
#include "MTA/LockAnalysis.h"
|
|
46
|
+
#include "MemoryModel/PointsTo.h"
|
|
47
|
+
#include <map>
|
|
48
|
+
#include <set>
|
|
49
|
+
#include <utility>
|
|
50
|
+
|
|
51
|
+
namespace SVF
|
|
52
|
+
{
|
|
53
|
+
|
|
54
|
+
class SlicedICFGView;
|
|
55
|
+
|
|
56
|
+
class MTASVFGBuilder : public SVFGBuilder
|
|
57
|
+
{
|
|
58
|
+
public:
|
|
59
|
+
typedef Set<const StmtSVFGNode*> SVFGNodeSet;
|
|
60
|
+
typedef NodeBS SVFGNodeIDSet;
|
|
61
|
+
|
|
62
|
+
/// Constructor: driven by the interleaving (MHP) and lock analyses.
|
|
63
|
+
MTASVFGBuilder(MHP* m, LockAnalysis* la) : SVFGBuilder(), mhp(m), lockana(la) {}
|
|
64
|
+
~MTASVFGBuilder() override = default;
|
|
65
|
+
|
|
66
|
+
/// Number of thread-aware (interference) SVFG edges added.
|
|
67
|
+
static u32_t numOfNewSVFGEdges;
|
|
68
|
+
|
|
69
|
+
/// Configure the builder for the main (post-slicing) FSAM solve rather than
|
|
70
|
+
/// the pre-analysis VFG_pre:
|
|
71
|
+
/// - slice != null restricts the interference-edge construction to kept
|
|
72
|
+
/// store/load nodes (a sliced-out endpoint's edge is inert in the gated
|
|
73
|
+
/// solve, so it need not be built);
|
|
74
|
+
/// - the [THREAD-VF] query map is skipped, as only VFG_pre slicing reads it.
|
|
75
|
+
/// The pre-analysis build leaves this unset (whole program, query map built).
|
|
76
|
+
void configureForMainSolve(const SlicedICFGView* slice)
|
|
77
|
+
{
|
|
78
|
+
icfgSlice = slice;
|
|
79
|
+
recordThreadVF = false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/// A candidate thread-aware value-flow edge s --o--> s' (src store, dst
|
|
83
|
+
/// load/store), keyed by its endpoint SVFG nodes.
|
|
84
|
+
typedef std::pair<const StmtSVFGNode*, const StmtSVFGNode*> ThreadVFEdge;
|
|
85
|
+
|
|
86
|
+
/// [THREAD-VF] per-edge query map (MSli §4.2, Fig. 6 rule [THREAD-VF]).
|
|
87
|
+
///
|
|
88
|
+
/// While building VFG_pre we record, for every candidate thread-aware
|
|
89
|
+
/// value-flow edge (s,s') the construction evaluates, its Query(s --o--> s')
|
|
90
|
+
/// set: the endpoints {s,s'} plus — under a common lock — the in-span
|
|
91
|
+
/// witnesses Succ_spl(s) / Pred_spl'(s') that decide TL/HD membership, i.e.
|
|
92
|
+
/// whether the edge survives the non-interference test (Def. 2). The query is
|
|
93
|
+
/// kept *per edge* (not pre-unioned) so ILA slicing can restrict the sources
|
|
94
|
+
/// to the edges that survive the FSPTA slice — ThreadVF(VFG'_pre) — rather
|
|
95
|
+
/// than every candidate pair. Feeding the retained edges' queries into ILA
|
|
96
|
+
/// slicing makes the sliced MHP/lock reproduce the same value-flow decisions
|
|
97
|
+
/// the main phase makes, while keeping the slice minimal.
|
|
98
|
+
///
|
|
99
|
+
/// The value stores only the additional lock-span witnesses; the endpoint
|
|
100
|
+
/// ICFG nodes are implicit in the key and consumers must add them back.
|
|
101
|
+
const std::map<ThreadVFEdge, std::set<const ICFGNode*>>& getThreadVFQueryMap() const
|
|
102
|
+
{
|
|
103
|
+
return threadVFQueryMap;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
protected:
|
|
107
|
+
/// Rewrite the SVFG build hook: build the stock SVFG, then add MHP edges.
|
|
108
|
+
void buildSVFG() override;
|
|
109
|
+
|
|
110
|
+
/// Inject a thread-aware MRGenerator so the MemSSA mod-ref carries the FSAM
|
|
111
|
+
/// fork/join side effects (relocated here from core MemRegion).
|
|
112
|
+
std::unique_ptr<MRGenerator> createMRGenerator(BVDataPTAImpl* pta, bool ptrOnlyMSSA) override;
|
|
113
|
+
|
|
114
|
+
private:
|
|
115
|
+
/// Main-solve configuration (see configureForMainSolve); defaults suit VFG_pre.
|
|
116
|
+
const SlicedICFGView* icfgSlice = nullptr; ///< null = whole program
|
|
117
|
+
bool recordThreadVF = true; ///< false = skip [THREAD-VF] recording
|
|
118
|
+
|
|
119
|
+
/// Collect the store/load SVFG nodes to pair for interference edges (all of
|
|
120
|
+
/// them, or -- when a slice is set -- only the kept ones).
|
|
121
|
+
void collectLoadStoreSVFGNodes();
|
|
122
|
+
|
|
123
|
+
/// FSAM join-related thread-oblivious value flow (the "return" half of
|
|
124
|
+
/// treating a join as a call without a forward): connect each start
|
|
125
|
+
/// routine's exit defs (FormalOUT) to the ActualOUT at every site that joins
|
|
126
|
+
/// it (FormalOUT -> ActualOUT ret edge). Done here as a post-pass over the
|
|
127
|
+
/// stock SVFG, so core SVFG.cpp stays unmodified.
|
|
128
|
+
void connectThreadJoinEdges();
|
|
129
|
+
|
|
130
|
+
/// Add a FormalOUT -> ActualOUT inter-procedural indirect ret edge for a
|
|
131
|
+
/// join, mirroring SVFG::addInterIndirectVFRetEdge using the public SVFG API
|
|
132
|
+
/// (points-to intersection + dedup via hasInterVFGEdge + addSVFGEdge).
|
|
133
|
+
void addJoinRetEdge(const FormalOUTSVFGNode* formalOut,
|
|
134
|
+
const ActualOUTSVFGNode* actualOut, CallSiteID csId);
|
|
135
|
+
|
|
136
|
+
/// Connect inter-thread (interference) value-flow edges for MHP pairs.
|
|
137
|
+
void connectMHPEdges(PointerAnalysis* pta);
|
|
138
|
+
|
|
139
|
+
void handleStoreLoad(const StmtSVFGNode* n1, const StmtSVFGNode* n2, PointerAnalysis* pta);
|
|
140
|
+
void handleStoreStore(const StmtSVFGNode* n1, const StmtSVFGNode* n2, PointerAnalysis* pta);
|
|
141
|
+
|
|
142
|
+
/// Record the [THREAD-VF] slicing sources for one candidate pair s --o--> s'
|
|
143
|
+
/// (s = src store, sp = dst load/store). Adds the endpoints, and — when the
|
|
144
|
+
/// pair is protected by a common lock — the in-span successor/predecessor
|
|
145
|
+
/// witnesses needed to re-decide the non-interference (tail/head) test.
|
|
146
|
+
void recordThreadVFSource(const StmtSVFGNode* s, const StmtSVFGNode* sp, bool commonLock);
|
|
147
|
+
|
|
148
|
+
/// Add a thread-MHP indirect value-flow edge srcId -> dstId carrying pts.
|
|
149
|
+
SVFGEdge* addTDEdge(NodeID srcId, NodeID dstId, const PointsTo& pts);
|
|
150
|
+
|
|
151
|
+
/// Lock-span head/tail tests (non-interference lock-pair pruning).
|
|
152
|
+
//@{
|
|
153
|
+
SVFGNodeIDSet getPrevNodes(const StmtSVFGNode* n);
|
|
154
|
+
SVFGNodeIDSet getSuccNodes(const StmtSVFGNode* n);
|
|
155
|
+
bool isHeadOfSpan(const StmtSVFGNode* n);
|
|
156
|
+
bool isTailOfSpan(const StmtSVFGNode* n);
|
|
157
|
+
//@}
|
|
158
|
+
|
|
159
|
+
SVFGNodeSet stnodeSet; ///< all store SVFG nodes
|
|
160
|
+
SVFGNodeSet ldnodeSet; ///< all load SVFG nodes
|
|
161
|
+
|
|
162
|
+
/// [THREAD-VF] per-edge query map (see getThreadVFQueryMap).
|
|
163
|
+
std::map<ThreadVFEdge, std::set<const ICFGNode*>> threadVFQueryMap;
|
|
164
|
+
|
|
165
|
+
MHP* mhp;
|
|
166
|
+
LockAnalysis* lockana;
|
|
167
|
+
|
|
168
|
+
Map<const StmtSVFGNode*, SVFGNodeIDSet> prevset;
|
|
169
|
+
Map<const StmtSVFGNode*, SVFGNodeIDSet> succset;
|
|
170
|
+
Map<const StmtSVFGNode*, bool> headmap;
|
|
171
|
+
Map<const StmtSVFGNode*, bool> tailmap;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
} // End namespace SVF
|
|
175
|
+
|
|
176
|
+
#endif /* INCLUDE_MTA_MTASVFGBUILDER_H_ */
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
//===- MTASlicer.h -- Multi-stage on-demand program slicers ---------------===//
|
|
2
|
+
//
|
|
3
|
+
// SVF: Static Value-Flow Analysis
|
|
4
|
+
//
|
|
5
|
+
// Copyright (C) <2013-> <Yulei Sui>
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
// This program is free software: you can redistribute it and/or modify
|
|
9
|
+
// it under the terms of the GNU Affero General Public License as published by
|
|
10
|
+
// the Free Software Foundation, either version 3 of the License, or
|
|
11
|
+
// (at your option) any later version.
|
|
12
|
+
|
|
13
|
+
// This program is distributed in the hope that it will be useful,
|
|
14
|
+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
// GNU Affero General Public License for more details.
|
|
17
|
+
|
|
18
|
+
// You should have received a copy of the GNU Affero General Public License
|
|
19
|
+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
20
|
+
//
|
|
21
|
+
//===----------------------------------------------------------------------===//
|
|
22
|
+
|
|
23
|
+
/*
|
|
24
|
+
* MTASlicer.h
|
|
25
|
+
*
|
|
26
|
+
* Author: Jiawei Yang
|
|
27
|
+
*
|
|
28
|
+
* The program slicers of "Multi-Stage On-Demand Program Slicing for Modular
|
|
29
|
+
* Analysis of Multi-Threaded Programs" (ISSTA 2026): a shared MTASlicerBase plus
|
|
30
|
+
* three concrete slicers.
|
|
31
|
+
* - MultiStageSlicer : ILA (sync + dual + call) slice for the thread-aware analysis
|
|
32
|
+
* (its FSPTA stage: data-dependence slice over the thread-aware VFG_pre)
|
|
33
|
+
* - SingleSlicer: one unified slice combining all three dependence kinds, shared
|
|
34
|
+
* by both ILA and FSPTA (the single-pass baseline, MSli §3/§5.4)
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
#ifndef MTA_MTASLICER_H
|
|
38
|
+
#define MTA_MTASLICER_H
|
|
39
|
+
|
|
40
|
+
#include "SVFIR/SVFIR.h"
|
|
41
|
+
#include "SVFIR/SVFStatements.h"
|
|
42
|
+
#include "SVFIR/SVFVariables.h"
|
|
43
|
+
#include "WPA/Andersen.h"
|
|
44
|
+
#include "MTA/MHP.h"
|
|
45
|
+
#include "MTA/LockAnalysis.h"
|
|
46
|
+
#include "MTA/TCT.h"
|
|
47
|
+
#include "Graphs/SlicedGraphs.h"
|
|
48
|
+
#include "Graphs/ThreadCallGraph.h"
|
|
49
|
+
#include "Graphs/ICFG.h"
|
|
50
|
+
#include "Graphs/ICFGNode.h"
|
|
51
|
+
#include <fstream>
|
|
52
|
+
#include "Graphs/ICFGEdge.h"
|
|
53
|
+
#include "Graphs/CallGraph.h"
|
|
54
|
+
#include "Util/WorkList.h"
|
|
55
|
+
#include <memory>
|
|
56
|
+
#include <set>
|
|
57
|
+
#include <string>
|
|
58
|
+
#include <unordered_map>
|
|
59
|
+
#include <unordered_set>
|
|
60
|
+
#include <vector>
|
|
61
|
+
#include <utility>
|
|
62
|
+
|
|
63
|
+
namespace SVF
|
|
64
|
+
{
|
|
65
|
+
|
|
66
|
+
// Forward declarations
|
|
67
|
+
class SVFG;
|
|
68
|
+
class VFGNode; // SVFGNode is a typedef for VFGNode
|
|
69
|
+
class PointerAnalysis;
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
//===----------------------------------------------------------------------===//
|
|
73
|
+
// SlicedTCT - the Thread-Create-Tree rebuilt over a SlicedThreadCallGraphView.
|
|
74
|
+
//
|
|
75
|
+
// Inherits TCT and overrides the ThreadCallGraph-traversing steps to use the
|
|
76
|
+
// sliced view. It sits at the sliced-representation layer (built from the view,
|
|
77
|
+
// consumed by the sliced MHP/LockAnalysis graph-access), which is why it lives
|
|
78
|
+
// here with the views rather than beside the analyses.
|
|
79
|
+
//===----------------------------------------------------------------------===//
|
|
80
|
+
class SlicedTCT : public TCT
|
|
81
|
+
{
|
|
82
|
+
public:
|
|
83
|
+
/// @param p PointerAnalysis (the shared Andersen pre-analysis)
|
|
84
|
+
/// @param slicedView SlicedSVFIRView containing a SlicedThreadCallGraphView
|
|
85
|
+
/// @param maxContextLen Max context length (0 = use Options::MaxContextLen())
|
|
86
|
+
SlicedTCT(PointerAnalysis* p, const SlicedSVFIRView* slicedView, u32_t maxContextLen = 0);
|
|
87
|
+
|
|
88
|
+
~SlicedTCT() override = default;
|
|
89
|
+
|
|
90
|
+
/// Override pushCxt to use the custom maxContextLen
|
|
91
|
+
void pushCxt(CallStrCxt& cxt, const CallICFGNode* call, const FunObjVar* callee) override;
|
|
92
|
+
|
|
93
|
+
protected:
|
|
94
|
+
void build() override;
|
|
95
|
+
void markRelProcs() override;
|
|
96
|
+
void markRelProcs(const FunObjVar* fun) override;
|
|
97
|
+
void collectLoopInfoForJoin() override;
|
|
98
|
+
void handleCallRelation(CxtThreadProc& ctp, const CallGraphEdge* cgEdge, const CallICFGNode* cs) override;
|
|
99
|
+
|
|
100
|
+
private:
|
|
101
|
+
void collectEntryFunInCallGraph() override;
|
|
102
|
+
|
|
103
|
+
const SlicedThreadCallGraphView* tcgView; // ThreadCallGraph view (from the sliced view)
|
|
104
|
+
u32_t maxContextLen; // 0 means use Options::MaxContextLen()
|
|
105
|
+
|
|
106
|
+
bool isKeptNode(const CallGraphNode* node) const;
|
|
107
|
+
bool isKeptEdge(const CallGraphEdge* edge) const;
|
|
108
|
+
void getKeptForkSites(std::vector<const ICFGNode*>& out) const;
|
|
109
|
+
void getKeptJoinSites(std::vector<const ICFGNode*>& out) const;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* MTASlicerBase - Base class for program slicing.
|
|
115
|
+
*
|
|
116
|
+
* Holds the shared helper methods and data members used by both concrete slicers
|
|
117
|
+
* (the ILA and FSPTA stages of MultiStageSlicer).
|
|
118
|
+
*/
|
|
119
|
+
class MTASlicerBase
|
|
120
|
+
{
|
|
121
|
+
public:
|
|
122
|
+
MTASlicerBase(SVFIR* svfIr, AndersenBase* pta, MHP* mhp,
|
|
123
|
+
LockAnalysis* lockAnalysis, SVFG* vfg = nullptr);
|
|
124
|
+
virtual ~MTASlicerBase();
|
|
125
|
+
|
|
126
|
+
protected:
|
|
127
|
+
SVFIR* svfIr;
|
|
128
|
+
AndersenBase* pta;
|
|
129
|
+
MHP* mhp;
|
|
130
|
+
LockAnalysis* lockAnalysis;
|
|
131
|
+
CallGraph* callGraph;
|
|
132
|
+
SVFG* vfg; ///< thread-aware VFG_pre (PTA/Single slicers; null for MTA)
|
|
133
|
+
|
|
134
|
+
// === Data flow analysis helper ===
|
|
135
|
+
/**
|
|
136
|
+
* Paper-faithful (§4.3) data-dependence slice over the thread-aware SVFG
|
|
137
|
+
* (VFG_pre): seed from the value-flow nodes of the given statements and
|
|
138
|
+
* backward-traverse every value-flow edge -- direct (top-level def-use),
|
|
139
|
+
* indirect (address-taken / MemSSA def-use), and thread-aware interference.
|
|
140
|
+
* Returns the kept ICFG nodes. This is the single dependence model used
|
|
141
|
+
* by the FSPTA stage.
|
|
142
|
+
*/
|
|
143
|
+
OrderedSet<const ICFGNode*> sliceDataDependenceOverVFG(
|
|
144
|
+
const OrderedSet<const SVFStmt*>& seeds, SVFG* vfg);
|
|
145
|
+
|
|
146
|
+
/// The SVFG-node granularity of the data-dependence slice above: the set of
|
|
147
|
+
/// VFG nodes reachable backward from the seeds. ThreadVF(VFG'_pre) is exactly
|
|
148
|
+
/// the thread-aware edges whose *both* endpoints lie in this set, so ILA
|
|
149
|
+
/// slicing uses it to restrict the [THREAD-VF] sources to surviving edges.
|
|
150
|
+
OrderedSet<const VFGNode*> computeDataDependenceSVFGNodes(
|
|
151
|
+
const OrderedSet<const SVFStmt*>& seeds, SVFG* vfg);
|
|
152
|
+
|
|
153
|
+
/// Project the retained VFG nodes (plus the seeds) onto their ICFG nodes.
|
|
154
|
+
OrderedSet<const ICFGNode*> svfgNodesToICFGNodes(
|
|
155
|
+
const OrderedSet<const VFGNode*>& nodes, const OrderedSet<const SVFStmt*>& seeds);
|
|
156
|
+
|
|
157
|
+
// === Thread analysis helpers ===
|
|
158
|
+
OrderedSet<const SVFStmt*> getDependentThreadCreate(const SVFStmt* stmt);
|
|
159
|
+
OrderedSet<const TCTNode*> getTCTNodeSetFromNode(const ICFGNode* node);
|
|
160
|
+
|
|
161
|
+
// === Lock analysis helpers ===
|
|
162
|
+
OrderedSet<const ICFGNode*> getLockSet(const ICFGNode* node);
|
|
163
|
+
OrderedSet<const CallICFGNode*> collectPthreadStatements(const OrderedSet<const SVFStmt*>& vulnerableStmts);
|
|
164
|
+
OrderedSet<const CallICFGNode*> collectMutexStatements(const OrderedSet<const SVFStmt*>& vulnerableStmts);
|
|
165
|
+
|
|
166
|
+
// === Common slicing helpers ===
|
|
167
|
+
/**
|
|
168
|
+
* Collect common pthread and mutex statements (shared by PTA and MTA slicing).
|
|
169
|
+
* @param vulnerableStatements Set of vulnerable statements
|
|
170
|
+
* @return Pair of (pthreadCallNodes, mutexCallNodes)
|
|
171
|
+
*/
|
|
172
|
+
std::pair<OrderedSet<const CallICFGNode*>, OrderedSet<const CallICFGNode*>>
|
|
173
|
+
collectCommonThreadStatements(const OrderedSet<const SVFStmt*>& vulnerableStatements);
|
|
174
|
+
|
|
175
|
+
// === ICFG analysis helpers ===
|
|
176
|
+
OrderedSet<const ICFGNode*> buildBackwardICFGNodeSet(const OrderedSet<const ICFGNode*>& vulnerableNodes);
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Call-dependence expansion (used by MultiStageSlicer): take the
|
|
180
|
+
* kept functions of the given nodes, close upward over the call graph
|
|
181
|
+
* (every transitive caller), then add each kept function's entry/exit nodes
|
|
182
|
+
* and the call/ret nodes of every call site targeting it.
|
|
183
|
+
* @param nodes Current set of ICFG nodes
|
|
184
|
+
* @return The input nodes plus the call/ret and entry/exit nodes above
|
|
185
|
+
*/
|
|
186
|
+
OrderedSet<const ICFGNode*> expandCallDependence(const OrderedSet<const ICFGNode*>& nodes);
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Perform dual slicing (temporal slicing): filter statements based on control flow and parallel execution.
|
|
190
|
+
* This is shared by both PTA and MTA slicing.
|
|
191
|
+
* @param slicedNodes Set of statements from statement-level slicing
|
|
192
|
+
* @return Set of ICFG nodes in the dual slice
|
|
193
|
+
*/
|
|
194
|
+
OrderedSet<const ICFGNode*> runDualSlicing(
|
|
195
|
+
const OrderedSet<const ICFGNode*>& slicedNodes);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* MultiStageSlicer - the multi-stage (differential) slicer of MSli: one class,
|
|
200
|
+
* two stages sharing one memoised data-dependence closure over VFG_pre.
|
|
201
|
+
* Stage 1 (ILA): runILASlicing -- synchronization/dual slicing + function
|
|
202
|
+
* expansion, feeding the sliced MHP/lock.
|
|
203
|
+
* Stage 2 (FSPTA): runPTASlicing -- backward data-dependence slice feeding
|
|
204
|
+
* the sliced flow-sensitive solve.
|
|
205
|
+
* Contrast: SingleSlicer below folds everything into ONE unified slice.
|
|
206
|
+
*/
|
|
207
|
+
class MultiStageSlicer : public MTASlicerBase
|
|
208
|
+
{
|
|
209
|
+
public:
|
|
210
|
+
MultiStageSlicer(SVFIR* svfIr, AndersenBase* pta, MHP* mhp,
|
|
211
|
+
LockAnalysis* lockAnalysis, SVFG* vfg = nullptr);
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Stage 1: the ILA slice (dual slicing + function expansion for the IRView).
|
|
215
|
+
* @param vulnerableStatements Set of vulnerable statements to start slicing from
|
|
216
|
+
* (the [INIT] rule: pre-analysis race statements).
|
|
217
|
+
* @param threadVFSources Extra ILA slicing sources from the [THREAD-VF] rule
|
|
218
|
+
* (MSli 4.2): statements whose MHP/lock-span results are queried during
|
|
219
|
+
* the main-phase thread-aware value-flow construction (endpoints and
|
|
220
|
+
* in-span non-interference witnesses collected while building VFG_pre).
|
|
221
|
+
* @return Set of ICFG nodes in the slice (including call/ret and entry/exit nodes)
|
|
222
|
+
*/
|
|
223
|
+
OrderedSet<const ICFGNode*> runILASlicing(
|
|
224
|
+
const OrderedSet<const SVFStmt*>& vulnerableStatements,
|
|
225
|
+
const OrderedSet<const ICFGNode*>& threadVFSources = {});
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Stage 2: the FSPTA slice (backward data dependence over the thread-aware
|
|
229
|
+
* VFG_pre; node set only, no function expansion).
|
|
230
|
+
*/
|
|
231
|
+
OrderedSet<const ICFGNode*> runPTASlicing(
|
|
232
|
+
const OrderedSet<const SVFStmt*>& vulnerableStatements);
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* The FSPTA data-dependence slice at SVFG-node granularity (memoised). The
|
|
236
|
+
* ILA stage queries this first, to restrict the [THREAD-VF] sources to
|
|
237
|
+
* ThreadVF(VFG'_pre); runPTASlicing reuses the same set, so the backward
|
|
238
|
+
* closure over VFG_pre is computed once and shared across both stages.
|
|
239
|
+
*/
|
|
240
|
+
const OrderedSet<const VFGNode*>& getRetainedSVFGNodes(
|
|
241
|
+
const OrderedSet<const SVFStmt*>& vulnerableStatements);
|
|
242
|
+
|
|
243
|
+
private:
|
|
244
|
+
OrderedSet<const VFGNode*> retainedSVFGNodes; ///< memoised data-dependence slice
|
|
245
|
+
bool retainedComputed = false;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* SingleSlicer - Unified slicer combining synchronization, data, and call
|
|
250
|
+
* dependence into ONE slice (the single-pass baseline, MSli §3/§5.4: the
|
|
251
|
+
* transitive closure of the target statements under the combined dependence
|
|
252
|
+
* graph). Both ILA and FSPTA run on this single slice, so V_ILA, V_PTA subset
|
|
253
|
+
* V_Single. Used by the differential-slicing ablation (-mta-slicing-single).
|
|
254
|
+
*
|
|
255
|
+
* Iteratively applies data dependence (over the thread-aware VFG_pre) and call
|
|
256
|
+
* dependence until convergence, then a single dual-slicing pass.
|
|
257
|
+
*/
|
|
258
|
+
class SingleSlicer : public MTASlicerBase
|
|
259
|
+
{
|
|
260
|
+
public:
|
|
261
|
+
SingleSlicer(SVFIR* svfIr, AndersenBase* pta, MHP* mhp,
|
|
262
|
+
LockAnalysis* lockAnalysis, SVFG* vfg = nullptr);
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Perform unified slicing combining synchronization, data, and call dependence.
|
|
266
|
+
* @param vulnerableStatements Set of vulnerable statements to start slicing from
|
|
267
|
+
* @return Set of ICFG nodes in the slice (including call/ret and entry/exit nodes)
|
|
268
|
+
*/
|
|
269
|
+
OrderedSet<const ICFGNode*> runSlicing(
|
|
270
|
+
const OrderedSet<const SVFStmt*>& vulnerableStatements);
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
} // End namespace SVF
|
|
274
|
+
|
|
275
|
+
#endif // MTA_MTASLICER_H
|