svf-tools 1.0.976 → 1.0.978
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/Graphs/ThreadCallGraph.h +0 -6
- package/svf/include/MTA/LockAnalysis.h +41 -31
- package/svf/include/MTA/MHP.h +34 -54
- package/svf/include/MTA/MTAStat.h +1 -2
- package/svf/include/MTA/TCT.h +36 -18
- package/svf/include/Util/CxtStmt.h +13 -12
- package/svf/include/Util/Options.h +1 -20
- package/svf/include/Util/SVFUtil.h +8 -43
- package/svf/include/Util/ThreadAPI.h +42 -85
- package/svf/lib/Graphs/ThreadCallGraph.cpp +1 -73
- package/svf/lib/MTA/LockAnalysis.cpp +83 -75
- package/svf/lib/MTA/MHP.cpp +142 -121
- package/svf/lib/MTA/MTA.cpp +2 -40
- package/svf/lib/MTA/MTAStat.cpp +7 -33
- package/svf/lib/MTA/TCT.cpp +30 -30
- package/svf/lib/Util/CallGraphBuilder.cpp +0 -15
- package/svf/lib/Util/Options.cpp +0 -62
- package/svf/lib/Util/ThreadAPI.cpp +27 -6
- package/svf-llvm/lib/SVFIRExtAPI.cpp +0 -26
- package/svf-llvm/tools/MTA/CMakeLists.txt +1 -1
- package/svf-llvm/tools/MTA/mta.cpp +0 -8
- package/svf/include/MTA/FSMPTA.h +0 -270
- package/svf/include/MTA/MTAResultValidator.h +0 -448
- package/svf/include/MTA/PCG.h +0 -229
- package/svf/lib/MTA/FSMPTA.cpp +0 -792
- package/svf/lib/MTA/PCG.cpp +0 -364
- package/svf-llvm/tools/MTA/LockResultValidator.cpp +0 -251
- package/svf-llvm/tools/MTA/LockResultValidator.h +0 -84
- package/svf-llvm/tools/MTA/MTAAnnotator.cpp +0 -293
- package/svf-llvm/tools/MTA/MTAAnnotator.h +0 -120
- package/svf-llvm/tools/MTA/MTAResultValidator.cpp +0 -716
- package/svf-llvm/tools/MTA/MTAResultValidator.h +0 -337
package/svf/lib/MTA/PCG.cpp
DELETED
|
@@ -1,364 +0,0 @@
|
|
|
1
|
-
//===- PCG.cpp -- Procedure creation graph-------------//
|
|
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
|
-
* PCG.cpp
|
|
25
|
-
*
|
|
26
|
-
* Created on: Jun 24, 2015
|
|
27
|
-
* Author: Yulei Sui, Peng Di
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
#include "Util/CommandLine.h"
|
|
31
|
-
#include "Util/Options.h"
|
|
32
|
-
#include "MTA/PCG.h"
|
|
33
|
-
#include "Util/SVFUtil.h"
|
|
34
|
-
|
|
35
|
-
using namespace SVF;
|
|
36
|
-
using namespace SVFUtil;
|
|
37
|
-
|
|
38
|
-
//=====================================================//
|
|
39
|
-
/*!
|
|
40
|
-
* Whether two functions may happen in parallel
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
//static Option<bool> TDPrint(
|
|
44
|
-
// "print-td",
|
|
45
|
-
// true,
|
|
46
|
-
// "Print Thread Analysis Results"
|
|
47
|
-
//);
|
|
48
|
-
|
|
49
|
-
bool PCG::analyze()
|
|
50
|
-
{
|
|
51
|
-
|
|
52
|
-
//callgraph = new CallGraph(mod);
|
|
53
|
-
|
|
54
|
-
DBOUT(DMTA, outs() << pasMsg("Starting MHP analysis\n"));
|
|
55
|
-
|
|
56
|
-
initFromThreadAPI(mod);
|
|
57
|
-
|
|
58
|
-
inferFromCallGraph();
|
|
59
|
-
|
|
60
|
-
//interferenceAnalysis();
|
|
61
|
-
|
|
62
|
-
//if (Options::TDPrint()) {
|
|
63
|
-
//printResults();
|
|
64
|
-
//tdAPI->performAPIStat(mod);
|
|
65
|
-
//}
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
bool PCG::mayHappenInParallelBetweenFunctions(const SVFFunction* fun1, const SVFFunction* fun2) const
|
|
70
|
-
{
|
|
71
|
-
// if neither of functions are spawnees, then they won't happen in parallel
|
|
72
|
-
if (isSpawneeFun(fun1) == false && isSpawneeFun(fun2) == false)
|
|
73
|
-
return false;
|
|
74
|
-
// if there exit one of the function are not spawner, spawnee or follower, then they won't happen in parallel
|
|
75
|
-
if (isSpawnerFun(fun1) == false && isSpawneeFun(fun1) == false && isFollowerFun(fun1) == false)
|
|
76
|
-
return false;
|
|
77
|
-
if (isSpawnerFun(fun2) == false && isSpawneeFun(fun2) == false && isFollowerFun(fun2) == false)
|
|
78
|
-
return false;
|
|
79
|
-
|
|
80
|
-
return true;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
bool PCG::mayHappenInParallel(const SVFInstruction* i1, const SVFInstruction* i2) const
|
|
84
|
-
{
|
|
85
|
-
const SVFFunction* fun1 = i1->getFunction();
|
|
86
|
-
const SVFFunction* fun2 = i2->getFunction();
|
|
87
|
-
return mayHappenInParallelBetweenFunctions(fun1, fun2);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
/*!
|
|
92
|
-
* Initialize thread spawners and spawnees from threadAPI functions
|
|
93
|
-
* a procedure is a spawner if it creates a thread and the created thread is still existent on its return
|
|
94
|
-
* a procedure is a spawnee if it is created by fork call
|
|
95
|
-
*/
|
|
96
|
-
void PCG::initFromThreadAPI(SVFModule* module)
|
|
97
|
-
{
|
|
98
|
-
for (const SVFFunction* fun : module->getFunctionSet())
|
|
99
|
-
{
|
|
100
|
-
for (const SVFBasicBlock* svfbb : fun->getBasicBlockList())
|
|
101
|
-
{
|
|
102
|
-
for (const SVFInstruction* inst : svfbb->getInstructionList())
|
|
103
|
-
{
|
|
104
|
-
if (tdAPI->isTDFork(inst))
|
|
105
|
-
{
|
|
106
|
-
const SVFValue* forkVal = tdAPI->getForkedFun(inst);
|
|
107
|
-
if (const SVFFunction* svForkfun = SVFUtil::dyn_cast<SVFFunction>(forkVal))
|
|
108
|
-
{
|
|
109
|
-
addSpawnsite(inst);
|
|
110
|
-
spawners.insert(fun);
|
|
111
|
-
spawnees.insert(svForkfun);
|
|
112
|
-
}
|
|
113
|
-
/// TODO: handle indirect call here for the fork Fun
|
|
114
|
-
else
|
|
115
|
-
{
|
|
116
|
-
writeWrnMsg("pthread create");
|
|
117
|
-
outs() << inst->toString() << "\n";
|
|
118
|
-
writeWrnMsg("invoke spawnee indirectly");
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/*!
|
|
127
|
-
* Infer spawners and spawnees from call graph. The inference are recursively done
|
|
128
|
-
* spawners: procedures may create a thread and return with the created thread still running
|
|
129
|
-
* spawnees: procedures may be executed as a spawned thread
|
|
130
|
-
* followers: procedures may be invoked by a thread after the thread returns from a spawner
|
|
131
|
-
* (procedure may be called after pthread_creat is called).
|
|
132
|
-
*/
|
|
133
|
-
void PCG::inferFromCallGraph()
|
|
134
|
-
{
|
|
135
|
-
|
|
136
|
-
collectSpawners();
|
|
137
|
-
|
|
138
|
-
collectSpawnees();
|
|
139
|
-
|
|
140
|
-
collectFollowers();
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/*!
|
|
144
|
-
* spawner: given a spawner, all its callers on callgraph are spawners
|
|
145
|
-
*/
|
|
146
|
-
void PCG::collectSpawners()
|
|
147
|
-
{
|
|
148
|
-
|
|
149
|
-
/// find all the spawners recursively on call graph
|
|
150
|
-
FunWorkList worklist;
|
|
151
|
-
for (FunSet::iterator it = spawners.begin(), eit = spawners.end(); it != eit; ++it)
|
|
152
|
-
{
|
|
153
|
-
worklist.push(*it);
|
|
154
|
-
}
|
|
155
|
-
while (!worklist.empty())
|
|
156
|
-
{
|
|
157
|
-
const SVFFunction* svffun = worklist.pop();
|
|
158
|
-
CallGraphNode* funNode = callgraph->getCallGraphNode(svffun);
|
|
159
|
-
for (CallGraphNode::const_iterator it = funNode->InEdgeBegin(), eit = funNode->InEdgeEnd(); it != eit;
|
|
160
|
-
++it)
|
|
161
|
-
{
|
|
162
|
-
CallGraphEdge* callEdge = (*it);
|
|
163
|
-
const SVFFunction* caller = callEdge->getSrcNode()->getFunction();
|
|
164
|
-
if (isSpawnerFun(caller) == false)
|
|
165
|
-
{
|
|
166
|
-
worklist.push(caller);
|
|
167
|
-
addSpawnerFun(caller);
|
|
168
|
-
}
|
|
169
|
-
/// add all the callsites from callers to callee (spawner) as a spawn site.
|
|
170
|
-
for (CallGraphEdge::CallInstSet::const_iterator dit = callEdge->directCallsBegin(), deit =
|
|
171
|
-
callEdge->directCallsEnd(); dit != deit; ++dit)
|
|
172
|
-
{
|
|
173
|
-
addSpawnsite((*dit)->getCallSite());
|
|
174
|
-
}
|
|
175
|
-
for (CallGraphEdge::CallInstSet::const_iterator dit = callEdge->indirectCallsBegin(), deit =
|
|
176
|
-
callEdge->indirectCallsEnd(); dit != deit; ++dit)
|
|
177
|
-
{
|
|
178
|
-
addSpawnsite((*dit)->getCallSite());
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/*!
|
|
185
|
-
* spawnee: given a spawnee, all its callees on callgraph are spawnees
|
|
186
|
-
*/
|
|
187
|
-
void PCG::collectSpawnees()
|
|
188
|
-
{
|
|
189
|
-
|
|
190
|
-
/// find all the spawnees recursively on call graph
|
|
191
|
-
FunWorkList worklist;
|
|
192
|
-
for (FunSet::iterator it = spawnees.begin(), eit = spawnees.end(); it != eit; ++it)
|
|
193
|
-
{
|
|
194
|
-
worklist.push(*it);
|
|
195
|
-
}
|
|
196
|
-
while (!worklist.empty())
|
|
197
|
-
{
|
|
198
|
-
const SVFFunction* svffun = worklist.pop();
|
|
199
|
-
CallGraphNode* funNode = callgraph->getCallGraphNode(svffun);
|
|
200
|
-
for (CallGraphNode::const_iterator it = funNode->OutEdgeBegin(), eit = funNode->OutEdgeEnd(); it != eit;
|
|
201
|
-
++it)
|
|
202
|
-
{
|
|
203
|
-
const SVFFunction* caller = (*it)->getDstNode()->getFunction();
|
|
204
|
-
if (isSpawneeFun(caller) == false)
|
|
205
|
-
{
|
|
206
|
-
worklist.push(caller);
|
|
207
|
-
addSpawneeFun(caller);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/*!
|
|
214
|
-
* Identify initial followers
|
|
215
|
-
* a procedure whose callsite lies in a control flow path that starts just after a spawner's callsite
|
|
216
|
-
*/
|
|
217
|
-
void PCG::identifyFollowers()
|
|
218
|
-
{
|
|
219
|
-
|
|
220
|
-
for (CallInstSet::const_iterator sit = spawnSitesBegin(), esit = spawnSitesEnd(); sit != esit; ++sit)
|
|
221
|
-
{
|
|
222
|
-
const SVFInstruction* inst = *sit;
|
|
223
|
-
BBWorkList bb_worklist;
|
|
224
|
-
Set<const SVFBasicBlock*> visitedBBs;
|
|
225
|
-
bb_worklist.push(inst->getParent());
|
|
226
|
-
while (!bb_worklist.empty())
|
|
227
|
-
{
|
|
228
|
-
const SVFBasicBlock* bb = bb_worklist.pop();
|
|
229
|
-
for (SVFBasicBlock::const_iterator it = bb->begin(), eit = bb->end(); it != eit; ++it)
|
|
230
|
-
{
|
|
231
|
-
const SVFInstruction* inst = *it;
|
|
232
|
-
// mark the callee of this callsite as follower
|
|
233
|
-
// if this is an call/invoke instruction but not a spawn site
|
|
234
|
-
if ((SVFUtil::isCallSite(inst)) && !isSpawnsite(inst) && !SVFUtil::isIntrinsicInst(inst))
|
|
235
|
-
{
|
|
236
|
-
CallICFGNode* cbn = getCallICFGNode(inst);
|
|
237
|
-
if (callgraph->hasCallGraphEdge(cbn))
|
|
238
|
-
{
|
|
239
|
-
for (CallGraph::CallGraphEdgeSet::const_iterator cgIt = callgraph->getCallEdgeBegin(cbn),
|
|
240
|
-
ecgIt = callgraph->getCallEdgeEnd(cbn); cgIt != ecgIt; ++cgIt)
|
|
241
|
-
{
|
|
242
|
-
const CallGraphEdge* edge = *cgIt;
|
|
243
|
-
addFollowerFun(edge->getDstNode()->getFunction());
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
for (const SVFBasicBlock* svf_scc_bb : bb->getSuccessors())
|
|
249
|
-
{
|
|
250
|
-
if (visitedBBs.count(svf_scc_bb) == 0)
|
|
251
|
-
{
|
|
252
|
-
visitedBBs.insert(svf_scc_bb);
|
|
253
|
-
bb_worklist.push(svf_scc_bb);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/*!
|
|
262
|
-
* collect follower procedures which may be called after pthread_create is invoked directly or indirectly
|
|
263
|
-
* a procedure which is called from a follower is also a follower.
|
|
264
|
-
*/
|
|
265
|
-
void PCG::collectFollowers()
|
|
266
|
-
{
|
|
267
|
-
|
|
268
|
-
/// identify initial followers
|
|
269
|
-
identifyFollowers();
|
|
270
|
-
|
|
271
|
-
/// find all the followers recursively on call graph
|
|
272
|
-
FunWorkList worklist;
|
|
273
|
-
for (FunSet::iterator it = followers.begin(), eit = followers.end(); it != eit; ++it)
|
|
274
|
-
{
|
|
275
|
-
worklist.push(*it);
|
|
276
|
-
}
|
|
277
|
-
while (!worklist.empty())
|
|
278
|
-
{
|
|
279
|
-
const SVFFunction* svffun = worklist.pop();
|
|
280
|
-
CallGraphNode* funNode = callgraph->getCallGraphNode(svffun);
|
|
281
|
-
for (CallGraphNode::const_iterator it = funNode->OutEdgeBegin(), eit = funNode->OutEdgeEnd(); it != eit;
|
|
282
|
-
++it)
|
|
283
|
-
{
|
|
284
|
-
const SVFFunction* caller = (*it)->getDstNode()->getFunction();
|
|
285
|
-
if (isFollowerFun(caller) == false)
|
|
286
|
-
{
|
|
287
|
-
worklist.push(caller);
|
|
288
|
-
addFollowerFun(caller);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/*!
|
|
295
|
-
* Thread interference analysis,
|
|
296
|
-
* Suppose we have a undirected graph G = {F,E,I}
|
|
297
|
-
* F denotes procedure,
|
|
298
|
-
* E represents interference edge (x,y) \in E, x \in F, y \in F
|
|
299
|
-
* means execution of x in one thread may overlap execution of y in another thread
|
|
300
|
-
* I(x,y) is a set of memory locations for this interference edge
|
|
301
|
-
*/
|
|
302
|
-
void PCG::interferenceAnalysis()
|
|
303
|
-
{
|
|
304
|
-
|
|
305
|
-
// DBOUT(DMTA, outs() << pasMsg("Starting Race Detection\n"));
|
|
306
|
-
|
|
307
|
-
PCG::FunVec worklist;
|
|
308
|
-
for (SVFModule::const_iterator F = mod->begin(), E = mod->end(); F != E; ++F)
|
|
309
|
-
{
|
|
310
|
-
const SVFFunction* fun = *F;
|
|
311
|
-
if (isExtCall(fun))
|
|
312
|
-
continue;
|
|
313
|
-
worklist.push_back(fun);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
while (!worklist.empty())
|
|
317
|
-
{
|
|
318
|
-
const SVFFunction* fun1 = worklist.back();
|
|
319
|
-
worklist.pop_back();
|
|
320
|
-
|
|
321
|
-
bool ismhpfun = false;
|
|
322
|
-
for (PCG::FunVec::iterator it = worklist.begin(), eit = worklist.end(); it != eit; ++it)
|
|
323
|
-
{
|
|
324
|
-
const SVFFunction* fun2 = *it;
|
|
325
|
-
if (mayHappenInParallelBetweenFunctions(fun1, fun2))
|
|
326
|
-
{
|
|
327
|
-
ismhpfun = true;
|
|
328
|
-
mhpfuns.insert(fun2);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
if (ismhpfun)
|
|
332
|
-
{
|
|
333
|
-
mhpfuns.insert(fun1);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/*!
|
|
339
|
-
* Print analysis results
|
|
340
|
-
*/
|
|
341
|
-
void PCG::printResults()
|
|
342
|
-
{
|
|
343
|
-
|
|
344
|
-
printTDFuns();
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/*!
|
|
348
|
-
* Print Thread sensitive properties for each function
|
|
349
|
-
*/
|
|
350
|
-
void PCG::printTDFuns()
|
|
351
|
-
{
|
|
352
|
-
|
|
353
|
-
for (SVFModule::const_iterator fi = mod->begin(), efi = mod->end(); fi != efi; ++fi)
|
|
354
|
-
{
|
|
355
|
-
const SVFFunction* fun = (*fi);
|
|
356
|
-
if (fun->isDeclaration())
|
|
357
|
-
continue;
|
|
358
|
-
|
|
359
|
-
std::string isSpawner = isSpawnerFun(fun) ? " SPAWNER " : "";
|
|
360
|
-
std::string isSpawnee = isSpawneeFun(fun) ? " CHILDREN " : "";
|
|
361
|
-
std::string isFollower = isFollowerFun(fun) ? " FOLLOWER " : "";
|
|
362
|
-
outs() << fun->getName() << " [" << isSpawner << isSpawnee << isFollower << "]\n";
|
|
363
|
-
}
|
|
364
|
-
}
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* LOCKResultValidator.cpp
|
|
3
|
-
*
|
|
4
|
-
* Created on: 24/07/2021
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
#include "Util/Options.h"
|
|
8
|
-
#include <string>
|
|
9
|
-
#include <sstream>
|
|
10
|
-
#include "LockResultValidator.h"
|
|
11
|
-
#include "MTAResultValidator.h"
|
|
12
|
-
#include "SVF-LLVM/LLVMModule.h"
|
|
13
|
-
|
|
14
|
-
using namespace SVF;
|
|
15
|
-
using namespace SVFUtil;
|
|
16
|
-
|
|
17
|
-
namespace SVF
|
|
18
|
-
{
|
|
19
|
-
|
|
20
|
-
// Subclassing RCResultValidator to define the abstract methods.
|
|
21
|
-
class RaceValidator : public RaceResultValidator
|
|
22
|
-
{
|
|
23
|
-
public:
|
|
24
|
-
RaceValidator(LockAnalysis* lockAnalysis) :lsa(lockAnalysis)
|
|
25
|
-
{
|
|
26
|
-
}
|
|
27
|
-
bool protectedByCommonLocks(const Instruction* I1, const Instruction* I2)
|
|
28
|
-
{
|
|
29
|
-
const SVFInstruction* inst1 = LLVMModuleSet::getLLVMModuleSet()->getSVFInstruction(I1);
|
|
30
|
-
const SVFInstruction* inst2 = LLVMModuleSet::getLLVMModuleSet()->getSVFInstruction(I2);
|
|
31
|
-
return lsa->isProtectedByCommonLock(inst1, inst2);
|
|
32
|
-
}
|
|
33
|
-
private:
|
|
34
|
-
LockAnalysis *lsa;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
} // End namespace SVF
|
|
38
|
-
|
|
39
|
-
Set<std::string> LockResultValidator::getStringArg(const Instruction* inst, unsigned int arg_num)
|
|
40
|
-
{
|
|
41
|
-
assert(LLVMUtil::isCallSite(inst) && "getFirstIntArg: inst is not a callsite");
|
|
42
|
-
const CallBase* cs = LLVMUtil::getLLVMCallSite(inst);
|
|
43
|
-
assert((arg_num < cs->arg_size()) && "Does not has this argument");
|
|
44
|
-
const GetElementPtrInst* gepinst = SVFUtil::dyn_cast<GetElementPtrInst>(cs->getArgOperand(arg_num));
|
|
45
|
-
const Constant* arrayinst = SVFUtil::dyn_cast<Constant>(gepinst->getOperand(0));
|
|
46
|
-
const ConstantDataArray* cxtarray = SVFUtil::dyn_cast<ConstantDataArray>(arrayinst->getOperand(0));
|
|
47
|
-
if (!cxtarray)
|
|
48
|
-
{
|
|
49
|
-
Set<std::string> strvec;
|
|
50
|
-
return strvec;
|
|
51
|
-
}
|
|
52
|
-
const std::string vthdcxtstring = cxtarray->getAsCString().str();
|
|
53
|
-
return split(vthdcxtstring, ',');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
Set<std::string> &LockResultValidator::split(const std::string &s, char delim, Set<std::string> &elems)
|
|
57
|
-
{
|
|
58
|
-
std::stringstream ss(s);
|
|
59
|
-
std::string item;
|
|
60
|
-
while (std::getline(ss, item, delim))
|
|
61
|
-
{
|
|
62
|
-
elems.insert(item);
|
|
63
|
-
}
|
|
64
|
-
return elems;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
Set<std::string> LockResultValidator::split(const std::string &s, char delim)
|
|
68
|
-
{
|
|
69
|
-
Set<std::string> elems;
|
|
70
|
-
split(s, delim, elems);
|
|
71
|
-
return elems;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
inline std::string LockResultValidator::getOutput(const char *scenario, LOCK_FLAG analysisRes)
|
|
75
|
-
{
|
|
76
|
-
std::string ret(scenario);
|
|
77
|
-
ret += "\t";
|
|
78
|
-
switch (analysisRes)
|
|
79
|
-
{
|
|
80
|
-
case LOCK_TRUE:
|
|
81
|
-
ret += SVFUtil::sucMsg("SUCCESS");
|
|
82
|
-
break;
|
|
83
|
-
case LOCK_UNSOUND:
|
|
84
|
-
ret += SVFUtil::bugMsg2("UNSOUND");
|
|
85
|
-
break;
|
|
86
|
-
case LOCK_IMPRECISE:
|
|
87
|
-
ret += SVFUtil::bugMsg1("IMPRECISE");
|
|
88
|
-
break;
|
|
89
|
-
default:
|
|
90
|
-
ret += SVFUtil::errMsg("FAILURE");
|
|
91
|
-
}
|
|
92
|
-
return ret;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
bool LockResultValidator::collectLockTargets()
|
|
96
|
-
{
|
|
97
|
-
const Function* F = nullptr;
|
|
98
|
-
for (Module &M : LLVMModuleSet::getLLVMModuleSet()->getLLVMModules())
|
|
99
|
-
{
|
|
100
|
-
for(auto it = M.begin(); it != M.end(); it++)
|
|
101
|
-
{
|
|
102
|
-
const std::string fName = (*it).getName().str();
|
|
103
|
-
if(fName.find(LOCK) != std::string::npos)
|
|
104
|
-
{
|
|
105
|
-
F = &(*it);
|
|
106
|
-
break;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
if (!F)
|
|
111
|
-
return false;
|
|
112
|
-
for(Value::const_use_iterator it = F->use_begin(), ie = F->use_end(); it!=ie; it++)
|
|
113
|
-
{
|
|
114
|
-
const Use *u = &*it;
|
|
115
|
-
const Value* user = u->getUser();
|
|
116
|
-
const Instruction* inst = SVFUtil::dyn_cast<Instruction>(user);
|
|
117
|
-
CxtLockSetStr y = getStringArg(inst, 0);
|
|
118
|
-
const Instruction* memInst = getPreviousMemoryAccessInst(inst);
|
|
119
|
-
const SVFInstruction* svfMemInst = LLVMModuleSet::getLLVMModuleSet()->getSVFInstruction(memInst);
|
|
120
|
-
|
|
121
|
-
instToCxtLockSet[svfMemInst] = y;
|
|
122
|
-
if(const StoreInst* store = SVFUtil::dyn_cast<StoreInst> (memInst))
|
|
123
|
-
{
|
|
124
|
-
if(const BinaryOperator* bop = SVFUtil::dyn_cast<BinaryOperator> (store->getValueOperand()))
|
|
125
|
-
{
|
|
126
|
-
const Value* v = bop->getOperand(0);
|
|
127
|
-
const Instruction* prevInst = SVFUtil::dyn_cast<LoadInst> (v);
|
|
128
|
-
const SVFInstruction* svfPrevInst = LLVMModuleSet::getLLVMModuleSet()->getSVFInstruction(prevInst);
|
|
129
|
-
instToCxtLockSet[svfPrevInst] = y;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
return true;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
LockResultValidator::LOCK_FLAG LockResultValidator::validateStmtInLock()
|
|
137
|
-
{
|
|
138
|
-
SVFIR* pag = SVFIR::getPAG();
|
|
139
|
-
LockResultValidator::LOCK_FLAG res = LockResultValidator::LOCK_TRUE;
|
|
140
|
-
LockAnalysis::CxtStmtToCxtLockSet analyedLS = _la->getCSTCLS();
|
|
141
|
-
for(LockAnalysis::CxtStmtToCxtLockSet::iterator it = analyedLS.begin(),
|
|
142
|
-
eit = analyedLS.end(); it!=eit; it++)
|
|
143
|
-
{
|
|
144
|
-
const SVFInstruction* inst = ((*it).first).getStmt();
|
|
145
|
-
bool interestedInst = true;
|
|
146
|
-
for(const SVFStmt* stmt : pag->getSVFStmtList(pag->getICFG()->getICFGNode(inst)))
|
|
147
|
-
{
|
|
148
|
-
if(!SVFUtil::isa<LoadStmt>(stmt) && !SVFUtil::isa<StoreStmt>(stmt))
|
|
149
|
-
interestedInst = false;
|
|
150
|
-
}
|
|
151
|
-
if(interestedInst==false)
|
|
152
|
-
continue;
|
|
153
|
-
const SVFFunction* F = inst->getFunction();
|
|
154
|
-
if(inFilter(F->getName()))
|
|
155
|
-
continue;
|
|
156
|
-
CxtLockSetStr LS = instToCxtLockSet[inst];
|
|
157
|
-
if(LS.size() != (*it).second.size())
|
|
158
|
-
{
|
|
159
|
-
if (Options::PrintValidRes())
|
|
160
|
-
{
|
|
161
|
-
outs() << errMsg("\nValidate Stmt's Lock : Wrong at: ") << inst->toString() << "\n";
|
|
162
|
-
outs() << "Reason: The number of lock on current stmt is wrong\n";
|
|
163
|
-
outs() << "\n----Given locks:\n";
|
|
164
|
-
for (CxtLockSetStr::iterator it1 = LS.begin(),eit1 = LS.end(); it1 != eit1; it++)
|
|
165
|
-
{
|
|
166
|
-
outs() << "Lock " << *it1 << " ";
|
|
167
|
-
}
|
|
168
|
-
outs() << "\n----Analysis locks:\n";
|
|
169
|
-
for (LockAnalysis::CxtLockSet::iterator it2 = (*it).second.begin(),
|
|
170
|
-
eit2 = (*it).second.end(); it2 != eit2; ++it)
|
|
171
|
-
{
|
|
172
|
-
const SVFInstruction* call = (*it2).getStmt();
|
|
173
|
-
outs()<<"Lock " << call->toString() << " ";
|
|
174
|
-
}
|
|
175
|
-
outs() << "\n";
|
|
176
|
-
}
|
|
177
|
-
res = LockResultValidator::LOCK_UNSOUND;
|
|
178
|
-
}
|
|
179
|
-
LockAnalysis::CxtLockSet LSA = (*it).second;
|
|
180
|
-
|
|
181
|
-
for(LockAnalysis::CxtLockSet::iterator it3 = LSA.begin(), eit3=LSA.end(); it3!=eit3; it3++)
|
|
182
|
-
{
|
|
183
|
-
const SVFInstruction* call = (*it3).getStmt();
|
|
184
|
-
if(SVFUtil::isCallSite(call) == false)
|
|
185
|
-
continue;
|
|
186
|
-
std::string lockName = SVFUtil::getSVFCallSite(call).getArgOperand(0)->getName();
|
|
187
|
-
if(!match(lockName, LS))
|
|
188
|
-
{
|
|
189
|
-
if(Options::PrintValidRes())
|
|
190
|
-
{
|
|
191
|
-
outs() << "\nValidate Stmt's Lock : Wrong at (" << inst->toString() << ")\n";
|
|
192
|
-
outs() << "Reason: The number of lock on current stmt is wrong\n";
|
|
193
|
-
outs() << "\n Lock " << lockName << " should not protect current instruction\n";
|
|
194
|
-
res = LockResultValidator::LOCK_IMPRECISE;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
return res;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
void LockResultValidator::analyze()
|
|
203
|
-
{
|
|
204
|
-
outs() << SVFUtil::pasMsg(" --- Lock Analysis Result Validation ---\n");
|
|
205
|
-
if(!collectLockTargets())
|
|
206
|
-
return;
|
|
207
|
-
std::string errstring;
|
|
208
|
-
errstring = getOutput("Validate Lock Analysis :", validateStmtInLock());
|
|
209
|
-
outs() << "======" << errstring << "======\n";
|
|
210
|
-
|
|
211
|
-
RaceValidator validator(_la);
|
|
212
|
-
validator.init(_la->getTCT()->getSVFModule());
|
|
213
|
-
validator.analyze();
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const Instruction* LockResultValidator::getPreviousMemoryAccessInst( const Instruction* I)
|
|
217
|
-
{
|
|
218
|
-
I = I->getPrevNode();
|
|
219
|
-
while (I)
|
|
220
|
-
{
|
|
221
|
-
if (SVFUtil::isa<LoadInst>(I) || SVFUtil::isa<StoreInst>(I))
|
|
222
|
-
return I;
|
|
223
|
-
SVFFunction* callee = nullptr;
|
|
224
|
-
|
|
225
|
-
if(LLVMUtil::isCallSite(I))
|
|
226
|
-
{
|
|
227
|
-
CallGraph::FunctionSet callees;
|
|
228
|
-
const SVFInstruction* svfInst = LLVMModuleSet::getLLVMModuleSet()->getSVFInstruction(I);
|
|
229
|
-
_la->getTCT()->getThreadCallGraph()->getCallees(getCBN(svfInst), callees);
|
|
230
|
-
|
|
231
|
-
for(CallGraph::FunctionSet::const_iterator cit = callees.begin(),
|
|
232
|
-
ecit = callees.end(); cit!=ecit; cit++)
|
|
233
|
-
{
|
|
234
|
-
if(*cit != nullptr)
|
|
235
|
-
{
|
|
236
|
-
callee = const_cast<SVFFunction*> (*cit);
|
|
237
|
-
break;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (callee)
|
|
244
|
-
{
|
|
245
|
-
if (callee->getName().find("llvm.memset") != std::string::npos)
|
|
246
|
-
return I;
|
|
247
|
-
}
|
|
248
|
-
I = I->getPrevNode();
|
|
249
|
-
}
|
|
250
|
-
return nullptr;
|
|
251
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* LOCKResultValidator.h
|
|
3
|
-
*
|
|
4
|
-
* Created on: 24/07/2021
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
#ifndef LOCKRESULTVALIDATOR_H_
|
|
10
|
-
#define LOCKRESULTVALIDATOR_H_
|
|
11
|
-
|
|
12
|
-
#include "MTA/LockAnalysis.h"
|
|
13
|
-
#include "SVF-LLVM/LLVMUtil.h"
|
|
14
|
-
|
|
15
|
-
/* Validate the result of lock analysis */
|
|
16
|
-
|
|
17
|
-
namespace SVF
|
|
18
|
-
{
|
|
19
|
-
class LockResultValidator
|
|
20
|
-
{
|
|
21
|
-
public:
|
|
22
|
-
typedef Set<std::string> CxtLockSetStr;
|
|
23
|
-
typedef Map<const SVFInstruction*, CxtLockSetStr> CxtStmtToCxtLockS;
|
|
24
|
-
|
|
25
|
-
typedef unsigned LOCK_FLAG;
|
|
26
|
-
|
|
27
|
-
LockResultValidator(LockAnalysis* la) : _la(la)
|
|
28
|
-
{
|
|
29
|
-
_mod = _la->getTCT()->getSVFModule();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
~LockResultValidator() {}
|
|
33
|
-
|
|
34
|
-
void analyze();
|
|
35
|
-
|
|
36
|
-
inline SVFModule* getModule() const
|
|
37
|
-
{
|
|
38
|
-
return _mod;
|
|
39
|
-
}
|
|
40
|
-
private:
|
|
41
|
-
// Get CallICFGNode
|
|
42
|
-
inline CallICFGNode* getCBN(const SVFInstruction* inst)
|
|
43
|
-
{
|
|
44
|
-
return _la->getTCT()->getCallICFGNode(inst);
|
|
45
|
-
}
|
|
46
|
-
const Instruction* getPreviousMemoryAccessInst( const Instruction* I);
|
|
47
|
-
|
|
48
|
-
inline bool inFilter(const std::string& name)
|
|
49
|
-
{
|
|
50
|
-
return filterFun.find(name) != filterFun.end();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
inline bool match(const std::string& lockName, CxtLockSetStr LS)
|
|
54
|
-
{
|
|
55
|
-
return LS.find(lockName) != LS.end();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
Set<std::string> &split(const std::string &s, char delim, Set<std::string> &elems);
|
|
59
|
-
Set<std::string> split(const std::string &s, char delim);
|
|
60
|
-
|
|
61
|
-
std::string getOutput(const char* scenario, LOCK_FLAG analysisRes);
|
|
62
|
-
|
|
63
|
-
Set<std::string> getStringArg(const Instruction* inst, unsigned int arg_num);
|
|
64
|
-
|
|
65
|
-
bool collectLockTargets();
|
|
66
|
-
LOCK_FLAG validateStmtInLock();
|
|
67
|
-
|
|
68
|
-
CxtStmtToCxtLockS instToCxtLockSet;
|
|
69
|
-
LockAnalysis::CxtStmtToCxtLockSet cxtStmtToCxtLockSet;
|
|
70
|
-
LockAnalysis::CxtLockSet cxtLockSet;
|
|
71
|
-
|
|
72
|
-
LockAnalysis* _la;
|
|
73
|
-
SVFModule* _mod;
|
|
74
|
-
|
|
75
|
-
static const LOCK_FLAG LOCK_TRUE = 0x01;
|
|
76
|
-
static const LOCK_FLAG LOCK_IMPRECISE = 0x02;
|
|
77
|
-
static const LOCK_FLAG LOCK_UNSOUND = 0x04;
|
|
78
|
-
|
|
79
|
-
static constexpr char const *LOCK = "LOCK";
|
|
80
|
-
|
|
81
|
-
Set<std::string> filterFun = {"LOCK", "INTERLEV_ACCESS", "PAUSE", "CXT_THREAD", "TCT_ACCESS"};
|
|
82
|
-
};
|
|
83
|
-
} // End namespace SVF
|
|
84
|
-
#endif /* LOCKRESULTVALIDATOR_H_ */
|