svf-tools 1.0.1072 → 1.0.1074
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/build.sh +0 -0
- package/package.json +1 -1
- package/svf/include/AE/Core/ICFGWTO.h +53 -0
- package/svf/include/AE/Svfexe/AbsExtAPI.h +0 -2
- package/svf/include/AE/Svfexe/AbstractInterpretation.h +31 -4
- package/svf/include/Util/Options.h +3 -0
- package/svf/lib/AE/Svfexe/AbsExtAPI.cpp +2 -0
- package/svf/lib/AE/Svfexe/AbstractInterpretation.cpp +216 -71
- package/svf/lib/Util/Options.cpp +13 -0
- package/svf-llvm/tools/AE/ae.cpp +1 -0
package/build.sh
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svf-tools",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1074",
|
|
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": {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
|
|
37
37
|
#include "Graphs/ICFG.h"
|
|
38
38
|
#include "Graphs/WTO.h"
|
|
39
|
+
#include "Graphs/CallGraph.h"
|
|
39
40
|
|
|
40
41
|
namespace SVF
|
|
41
42
|
{
|
|
@@ -77,6 +78,58 @@ public:
|
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
};
|
|
81
|
+
|
|
82
|
+
// Added for IWTO
|
|
83
|
+
class ICFGIWTO : public ICFGWTO
|
|
84
|
+
{
|
|
85
|
+
public:
|
|
86
|
+
typedef ICFGWTO Base;
|
|
87
|
+
typedef WTOComponentVisitor<ICFG>::WTONodeT ICFGWTONode;
|
|
88
|
+
NodeBS &funcPar;
|
|
89
|
+
CallGraph *cg;
|
|
90
|
+
|
|
91
|
+
explicit ICFGIWTO(ICFG* graph, const ICFGNode* node, NodeBS & funcPar, CallGraph* cg) :
|
|
92
|
+
Base(graph, node), funcPar(funcPar), cg(cg) {}
|
|
93
|
+
|
|
94
|
+
virtual ~ICFGIWTO()
|
|
95
|
+
{
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
inline void forEachSuccessor(
|
|
99
|
+
const ICFGNode* node,
|
|
100
|
+
std::function<void(const ICFGNode*)> func) const override
|
|
101
|
+
{
|
|
102
|
+
if (const auto* callNode = SVFUtil::dyn_cast<CallICFGNode>(node))
|
|
103
|
+
{
|
|
104
|
+
|
|
105
|
+
for (const auto &e : callNode->getOutEdges())
|
|
106
|
+
{
|
|
107
|
+
ICFGNode *calleeEntryICFGNode = e->getDstNode();
|
|
108
|
+
CallGraphNode * calleeCGNode = cg->getCallGraphNode(calleeEntryICFGNode->getFun());
|
|
109
|
+
|
|
110
|
+
const ICFGNode* succ = nullptr;
|
|
111
|
+
if (funcPar.test(calleeCGNode->getId()))
|
|
112
|
+
succ = calleeEntryICFGNode;
|
|
113
|
+
else
|
|
114
|
+
succ = callNode->getRetICFGNode();
|
|
115
|
+
|
|
116
|
+
func(succ);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else
|
|
120
|
+
{
|
|
121
|
+
for (const auto& e : node->getOutEdges())
|
|
122
|
+
{
|
|
123
|
+
ICFGNode *succ = e->getDstNode();
|
|
124
|
+
CallGraphNode *succCGNode = cg->getCallGraphNode(succ->getFun());
|
|
125
|
+
if (!funcPar.test(succCGNode->getId()))
|
|
126
|
+
continue;
|
|
127
|
+
func(succ);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
80
133
|
} // namespace SVF
|
|
81
134
|
|
|
82
135
|
#endif // SVF_ICFGWTO_H
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
#include "AE/Svfexe/AEDetector.h"
|
|
34
34
|
#include "AE/Svfexe/AbsExtAPI.h"
|
|
35
35
|
#include "Util/SVFBugReport.h"
|
|
36
|
-
#include "
|
|
36
|
+
#include "Util/SVFStat.h"
|
|
37
|
+
#include "Graphs/SCC.h"
|
|
37
38
|
|
|
38
39
|
namespace SVF
|
|
39
40
|
{
|
|
@@ -107,6 +108,29 @@ class AbstractInterpretation
|
|
|
107
108
|
|
|
108
109
|
public:
|
|
109
110
|
typedef SCCDetection<CallGraph*> CallGraphSCC;
|
|
111
|
+
|
|
112
|
+
/*
|
|
113
|
+
* For recursive test case
|
|
114
|
+
* int demo(int a) {
|
|
115
|
+
if (a >= 10000)
|
|
116
|
+
return a;
|
|
117
|
+
demo(a+1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
int main() {
|
|
121
|
+
int result = demo(0);
|
|
122
|
+
}
|
|
123
|
+
* if set TOP, result = [-oo, +oo] since the return value, and any stored object pointed by q at *q = p in recursive functions will be set to the top value.
|
|
124
|
+
* if set WIDEN_ONLY, result = [10000, +oo] since only widening is applied at the cycle head of recursive functions without narrowing.
|
|
125
|
+
* if set WIDEN_NARROW, result = [10000, 10000] since both widening and narrowing are applied at the cycle head of recursive functions.
|
|
126
|
+
* */
|
|
127
|
+
enum HandleRecur
|
|
128
|
+
{
|
|
129
|
+
TOP,
|
|
130
|
+
WIDEN_ONLY,
|
|
131
|
+
WIDEN_NARROW
|
|
132
|
+
};
|
|
133
|
+
|
|
110
134
|
/// Constructor
|
|
111
135
|
AbstractInterpretation();
|
|
112
136
|
|
|
@@ -135,7 +159,7 @@ private:
|
|
|
135
159
|
/// Global ICFGNode is handled at the entry of the program,
|
|
136
160
|
virtual void handleGlobalNode();
|
|
137
161
|
|
|
138
|
-
///
|
|
162
|
+
/// Compute IWTO for each function partition entry
|
|
139
163
|
void initWTO();
|
|
140
164
|
|
|
141
165
|
/**
|
|
@@ -251,7 +275,8 @@ private:
|
|
|
251
275
|
AEStat* stat;
|
|
252
276
|
|
|
253
277
|
std::vector<const CallICFGNode*> callSiteStack;
|
|
254
|
-
Map<const FunObjVar*, ICFGWTO*> funcToWTO;
|
|
278
|
+
Map<const FunObjVar*, const ICFGWTO*> funcToWTO;
|
|
279
|
+
Set<std::pair<const CallICFGNode*, NodeID>> nonRecursiveCallSites;
|
|
255
280
|
Set<const FunObjVar*> recursiveFuns;
|
|
256
281
|
|
|
257
282
|
|
|
@@ -282,8 +307,10 @@ private:
|
|
|
282
307
|
// helper functions in handleCallSite
|
|
283
308
|
virtual bool isExtCall(const CallICFGNode* callNode);
|
|
284
309
|
virtual void extCallPass(const CallICFGNode* callNode);
|
|
310
|
+
virtual bool isRecursiveFun(const FunObjVar* fun);
|
|
285
311
|
virtual bool isRecursiveCall(const CallICFGNode* callNode);
|
|
286
|
-
virtual void recursiveCallPass(const CallICFGNode*
|
|
312
|
+
virtual void recursiveCallPass(const CallICFGNode *callNode);
|
|
313
|
+
virtual bool isRecursiveCallSite(const CallICFGNode* callNode, const FunObjVar *);
|
|
287
314
|
virtual bool isDirectCall(const CallICFGNode* callNode);
|
|
288
315
|
virtual void directCallFunPass(const CallICFGNode* callNode);
|
|
289
316
|
virtual bool isIndirectCall(const CallICFGNode* callNode);
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#include "Util/NodeIDAllocator.h"
|
|
12
12
|
#include "MSSA/MemSSA.h"
|
|
13
13
|
#include "WPA/WPAPass.h"
|
|
14
|
+
#include "AE/Svfexe/AbstractInterpretation.h"
|
|
14
15
|
|
|
15
16
|
namespace SVF
|
|
16
17
|
{
|
|
@@ -244,6 +245,8 @@ public:
|
|
|
244
245
|
|
|
245
246
|
// Abstract Execution
|
|
246
247
|
static const Option<u32_t> WidenDelay;
|
|
248
|
+
/// recursion handling mode, Default: TOP
|
|
249
|
+
static const OptionMap<AbstractInterpretation::HandleRecur> HandleRecur;
|
|
247
250
|
/// the max time consumptions (seconds). Default: 4 hours 14400s
|
|
248
251
|
static const Option<u32_t> Timeout;
|
|
249
252
|
/// bug info output file, Default: output.db
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
//
|
|
27
27
|
#include "AE/Svfexe/AbsExtAPI.h"
|
|
28
28
|
#include "AE/Svfexe/AbstractInterpretation.h"
|
|
29
|
+
#include "WPA/Andersen.h"
|
|
30
|
+
#include "Util/Options.h"
|
|
29
31
|
|
|
30
32
|
using namespace SVF;
|
|
31
33
|
AbsExtAPI::AbsExtAPI(Map<const ICFGNode*, AbstractState>& traces): abstractTrace(traces)
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
#include "Util/Options.h"
|
|
32
32
|
#include "Util/WorkList.h"
|
|
33
33
|
#include "Graphs/CallGraph.h"
|
|
34
|
+
#include "WPA/Andersen.h"
|
|
34
35
|
#include <cmath>
|
|
35
36
|
|
|
36
37
|
using namespace SVF;
|
|
@@ -68,15 +69,16 @@ AbstractInterpretation::~AbstractInterpretation()
|
|
|
68
69
|
delete stat;
|
|
69
70
|
for (auto it: funcToWTO)
|
|
70
71
|
delete it.second;
|
|
71
|
-
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
/**
|
|
75
|
-
* @brief
|
|
75
|
+
* @brief Compute WTO for each function partition entry
|
|
76
76
|
*
|
|
77
|
-
* This function identifies
|
|
78
|
-
*
|
|
79
|
-
*
|
|
77
|
+
* This function first identifies function partition entries (pair: <entry, function set>),
|
|
78
|
+
* and then compute the IWTO for each pair.
|
|
79
|
+
* It does this by detecting call graph's strongly connected components (SCC).
|
|
80
|
+
* Each SCC forms a function partition, and any function that is invoked from outside its SCC
|
|
81
|
+
* is identified as an entry of the function partition.
|
|
80
82
|
*/
|
|
81
83
|
void AbstractInterpretation::initWTO()
|
|
82
84
|
{
|
|
@@ -84,21 +86,74 @@ void AbstractInterpretation::initWTO()
|
|
|
84
86
|
// Detect if the call graph has cycles by finding its strongly connected components (SCC)
|
|
85
87
|
Andersen::CallGraphSCC* callGraphScc = ander->getCallGraphSCC();
|
|
86
88
|
callGraphScc->find();
|
|
87
|
-
CallGraph*
|
|
89
|
+
CallGraph* callGraph = ander->getCallGraph();
|
|
88
90
|
|
|
89
91
|
// Iterate through the call graph
|
|
90
|
-
for (auto it =
|
|
92
|
+
for (auto it = callGraph->begin(); it != callGraph->end(); it++)
|
|
91
93
|
{
|
|
92
94
|
// Check if the current function is part of a cycle
|
|
93
95
|
if (callGraphScc->isInCycle(it->second->getId()))
|
|
94
96
|
recursiveFuns.insert(it->second->getFunction()); // Mark the function as recursive
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
|
|
98
|
+
// In TOP mode, calculate the WTO
|
|
99
|
+
if (Options::HandleRecur() == TOP)
|
|
100
|
+
{
|
|
101
|
+
if (it->second->getFunction()->isDeclaration())
|
|
102
|
+
continue;
|
|
103
|
+
auto* wto = new ICFGWTO(icfg, icfg->getFunEntryICFGNode(it->second->getFunction()));
|
|
104
|
+
wto->init();
|
|
105
|
+
funcToWTO[it->second->getFunction()] = wto;
|
|
106
|
+
}
|
|
107
|
+
// In WIDEN_TOP or WIDEN_NARROW mode, calculate the IWTO
|
|
108
|
+
else if (Options::HandleRecur() == WIDEN_ONLY ||
|
|
109
|
+
Options::HandleRecur() == WIDEN_NARROW)
|
|
110
|
+
{
|
|
111
|
+
const FunObjVar *fun = it->second->getFunction();
|
|
112
|
+
if (fun->isDeclaration())
|
|
113
|
+
continue;
|
|
114
|
+
|
|
115
|
+
NodeID repNodeId = callGraphScc->repNode(it->second->getId());
|
|
116
|
+
auto cgSCCNodes = callGraphScc->subNodes(repNodeId);
|
|
117
|
+
|
|
118
|
+
// Identify if this node is an SCC entry (nodes who have incoming edges
|
|
119
|
+
// from nodes outside the SCC). Also identify non-recursive callsites.
|
|
120
|
+
bool isEntry = false;
|
|
121
|
+
if (it->second->getInEdges().empty())
|
|
122
|
+
isEntry = true;
|
|
123
|
+
for (auto inEdge: it->second->getInEdges())
|
|
124
|
+
{
|
|
125
|
+
NodeID srcNodeId = inEdge->getSrcID();
|
|
126
|
+
if (!cgSCCNodes.test(srcNodeId))
|
|
127
|
+
{
|
|
128
|
+
isEntry = true;
|
|
129
|
+
const CallICFGNode *callSite = nullptr;
|
|
130
|
+
if (inEdge->isDirectCallEdge())
|
|
131
|
+
callSite = *(inEdge->getDirectCalls().begin());
|
|
132
|
+
else if (inEdge->isIndirectCallEdge())
|
|
133
|
+
callSite = *(inEdge->getIndirectCalls().begin());
|
|
134
|
+
else
|
|
135
|
+
assert(false && "CallGraphEdge must "
|
|
136
|
+
"be either direct or indirect!");
|
|
137
|
+
|
|
138
|
+
nonRecursiveCallSites.insert(
|
|
139
|
+
{callSite, inEdge->getDstNode()->getFunction()->getId()});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Compute IWTO for the function partition entered from each partition entry
|
|
144
|
+
if (isEntry)
|
|
145
|
+
{
|
|
146
|
+
ICFGIWTO* iwto = new ICFGIWTO(icfg, icfg->getFunEntryICFGNode(fun),
|
|
147
|
+
cgSCCNodes, callGraph);
|
|
148
|
+
iwto->init();
|
|
149
|
+
funcToWTO[it->second->getFunction()] = iwto;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else
|
|
153
|
+
assert(false && "Invalid recursion mode specified!");
|
|
100
154
|
}
|
|
101
155
|
}
|
|
156
|
+
|
|
102
157
|
/// Program entry
|
|
103
158
|
void AbstractInterpretation::analyse()
|
|
104
159
|
{
|
|
@@ -109,7 +164,7 @@ void AbstractInterpretation::analyse()
|
|
|
109
164
|
icfg->getGlobalICFGNode())[PAG::getPAG()->getBlkPtr()] = IntervalValue::top();
|
|
110
165
|
if (const CallGraphNode* cgn = svfir->getCallGraph()->getCallGraphNode("main"))
|
|
111
166
|
{
|
|
112
|
-
ICFGWTO* wto = funcToWTO[cgn->getFunction()];
|
|
167
|
+
const ICFGWTO* wto = funcToWTO[cgn->getFunction()];
|
|
113
168
|
handleWTOComponents(wto->getWTOComponents());
|
|
114
169
|
}
|
|
115
170
|
}
|
|
@@ -138,27 +193,57 @@ bool AbstractInterpretation::mergeStatesFromPredecessors(const ICFGNode * icfgNo
|
|
|
138
193
|
{
|
|
139
194
|
if (abstractTrace.find(edge->getSrcNode()) != abstractTrace.end())
|
|
140
195
|
{
|
|
141
|
-
|
|
142
|
-
if (
|
|
196
|
+
|
|
197
|
+
if (const IntraCFGEdge *intraCfgEdge =
|
|
198
|
+
SVFUtil::dyn_cast<IntraCFGEdge>(edge))
|
|
143
199
|
{
|
|
144
200
|
AbstractState tmpEs = abstractTrace[edge->getSrcNode()];
|
|
145
|
-
if (
|
|
201
|
+
if (intraCfgEdge->getCondition())
|
|
146
202
|
{
|
|
147
|
-
|
|
203
|
+
if (isBranchFeasible(intraCfgEdge, tmpEs))
|
|
204
|
+
{
|
|
205
|
+
workList.push_back(tmpEs);
|
|
206
|
+
}
|
|
207
|
+
else
|
|
208
|
+
{
|
|
209
|
+
// do nothing
|
|
210
|
+
}
|
|
148
211
|
}
|
|
149
212
|
else
|
|
150
213
|
{
|
|
151
|
-
|
|
214
|
+
workList.push_back(tmpEs);
|
|
152
215
|
}
|
|
153
216
|
}
|
|
154
|
-
else
|
|
217
|
+
else if (const CallCFGEdge *callCfgEdge =
|
|
218
|
+
SVFUtil::dyn_cast<CallCFGEdge>(edge))
|
|
155
219
|
{
|
|
156
|
-
workList.push_back(abstractTrace[edge->getSrcNode()]);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
else
|
|
160
|
-
{
|
|
161
220
|
|
|
221
|
+
// context insensitive implementation
|
|
222
|
+
workList.push_back(
|
|
223
|
+
abstractTrace[callCfgEdge->getSrcNode()]);
|
|
224
|
+
}
|
|
225
|
+
else if (const RetCFGEdge *retCfgEdge =
|
|
226
|
+
SVFUtil::dyn_cast<RetCFGEdge>(edge))
|
|
227
|
+
{
|
|
228
|
+
switch (Options::HandleRecur())
|
|
229
|
+
{
|
|
230
|
+
case TOP:
|
|
231
|
+
{
|
|
232
|
+
workList.push_back(abstractTrace[retCfgEdge->getSrcNode()]);
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
case WIDEN_ONLY:
|
|
236
|
+
case WIDEN_NARROW:
|
|
237
|
+
{
|
|
238
|
+
const RetICFGNode* returnSite = SVFUtil::dyn_cast<RetICFGNode>(icfgNode);
|
|
239
|
+
const CallICFGNode* callSite = returnSite->getCallICFGNode();
|
|
240
|
+
if (hasAbsStateFromTrace(callSite))
|
|
241
|
+
workList.push_back(abstractTrace[retCfgEdge->getSrcNode()]);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
else
|
|
246
|
+
assert(false && "Unhandled ICFGEdge type encountered!");
|
|
162
247
|
}
|
|
163
248
|
}
|
|
164
249
|
if (workList.size() == 0)
|
|
@@ -502,7 +587,7 @@ void AbstractInterpretation::handleSingletonWTO(const ICFGSingletonWTO *icfgSing
|
|
|
502
587
|
}
|
|
503
588
|
|
|
504
589
|
/**
|
|
505
|
-
* @brief
|
|
590
|
+
* @brief Handle two types of WTO components (singleton and cycle)
|
|
506
591
|
*/
|
|
507
592
|
void AbstractInterpretation::handleWTOComponents(const std::list<const ICFGWTOComp*>& wtoComps)
|
|
508
593
|
{
|
|
@@ -512,7 +597,7 @@ void AbstractInterpretation::handleWTOComponents(const std::list<const ICFGWTOCo
|
|
|
512
597
|
}
|
|
513
598
|
}
|
|
514
599
|
|
|
515
|
-
void AbstractInterpretation::handleWTOComponent(const
|
|
600
|
+
void AbstractInterpretation::handleWTOComponent(const ICFGWTOComp* wtoNode)
|
|
516
601
|
{
|
|
517
602
|
if (const ICFGSingletonWTO* node = SVFUtil::dyn_cast<ICFGSingletonWTO>(wtoNode))
|
|
518
603
|
{
|
|
@@ -527,9 +612,7 @@ void AbstractInterpretation::handleWTOComponent(const SVF::ICFGWTOComp* wtoNode)
|
|
|
527
612
|
}
|
|
528
613
|
// Assert false for unknown WTO types
|
|
529
614
|
else
|
|
530
|
-
{
|
|
531
615
|
assert(false && "unknown WTO type!");
|
|
532
|
-
}
|
|
533
616
|
}
|
|
534
617
|
|
|
535
618
|
void AbstractInterpretation::handleCallSite(const ICFGNode* node)
|
|
@@ -540,7 +623,7 @@ void AbstractInterpretation::handleCallSite(const ICFGNode* node)
|
|
|
540
623
|
{
|
|
541
624
|
extCallPass(callNode);
|
|
542
625
|
}
|
|
543
|
-
else if (isRecursiveCall(callNode))
|
|
626
|
+
else if (isRecursiveCall(callNode) && Options::HandleRecur() == TOP)
|
|
544
627
|
{
|
|
545
628
|
recursiveCallPass(callNode);
|
|
546
629
|
}
|
|
@@ -553,22 +636,18 @@ void AbstractInterpretation::handleCallSite(const ICFGNode* node)
|
|
|
553
636
|
indirectCallFunPass(callNode);
|
|
554
637
|
}
|
|
555
638
|
else
|
|
556
|
-
{
|
|
557
639
|
assert(false && "implement this part");
|
|
558
|
-
}
|
|
559
640
|
}
|
|
560
641
|
else
|
|
561
|
-
{
|
|
562
642
|
assert (false && "it is not call node");
|
|
563
|
-
}
|
|
564
643
|
}
|
|
565
644
|
|
|
566
|
-
bool AbstractInterpretation::isExtCall(const
|
|
645
|
+
bool AbstractInterpretation::isExtCall(const CallICFGNode *callNode)
|
|
567
646
|
{
|
|
568
647
|
return SVFUtil::isExtCall(callNode->getCalledFunction());
|
|
569
648
|
}
|
|
570
649
|
|
|
571
|
-
void AbstractInterpretation::extCallPass(const
|
|
650
|
+
void AbstractInterpretation::extCallPass(const CallICFGNode *callNode)
|
|
572
651
|
{
|
|
573
652
|
callSiteStack.push_back(callNode);
|
|
574
653
|
utils->handleExtAPI(callNode);
|
|
@@ -579,16 +658,21 @@ void AbstractInterpretation::extCallPass(const SVF::CallICFGNode *callNode)
|
|
|
579
658
|
callSiteStack.pop_back();
|
|
580
659
|
}
|
|
581
660
|
|
|
582
|
-
bool AbstractInterpretation::
|
|
661
|
+
bool AbstractInterpretation::isRecursiveFun(const FunObjVar* fun)
|
|
662
|
+
{
|
|
663
|
+
return recursiveFuns.find(fun) != recursiveFuns.end();
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
bool AbstractInterpretation::isRecursiveCall(const CallICFGNode *callNode)
|
|
583
667
|
{
|
|
584
668
|
const FunObjVar *callfun = callNode->getCalledFunction();
|
|
585
669
|
if (!callfun)
|
|
586
670
|
return false;
|
|
587
671
|
else
|
|
588
|
-
return
|
|
672
|
+
return isRecursiveFun(callfun);
|
|
589
673
|
}
|
|
590
674
|
|
|
591
|
-
void AbstractInterpretation::recursiveCallPass(const
|
|
675
|
+
void AbstractInterpretation::recursiveCallPass(const CallICFGNode *callNode)
|
|
592
676
|
{
|
|
593
677
|
AbstractState& as = getAbsStateFromTrace(callNode);
|
|
594
678
|
SkipRecursiveCall(callNode);
|
|
@@ -607,23 +691,37 @@ void AbstractInterpretation::recursiveCallPass(const SVF::CallICFGNode *callNode
|
|
|
607
691
|
abstractTrace[retNode] = as;
|
|
608
692
|
}
|
|
609
693
|
|
|
610
|
-
bool AbstractInterpretation::
|
|
694
|
+
bool AbstractInterpretation::isRecursiveCallSite(const CallICFGNode* callNode,
|
|
695
|
+
const FunObjVar* callee)
|
|
696
|
+
{
|
|
697
|
+
return nonRecursiveCallSites.find({callNode, callee->getId()}) ==
|
|
698
|
+
nonRecursiveCallSites.end();
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
bool AbstractInterpretation::isDirectCall(const CallICFGNode *callNode)
|
|
611
702
|
{
|
|
612
703
|
const FunObjVar *callfun =callNode->getCalledFunction();
|
|
613
704
|
if (!callfun)
|
|
614
705
|
return false;
|
|
615
706
|
else
|
|
616
|
-
return
|
|
707
|
+
return !callfun->isDeclaration();
|
|
617
708
|
}
|
|
618
|
-
void AbstractInterpretation::directCallFunPass(const
|
|
709
|
+
void AbstractInterpretation::directCallFunPass(const CallICFGNode *callNode)
|
|
619
710
|
{
|
|
620
711
|
AbstractState& as = getAbsStateFromTrace(callNode);
|
|
621
|
-
callSiteStack.push_back(callNode);
|
|
622
712
|
|
|
623
713
|
abstractTrace[callNode] = as;
|
|
624
714
|
|
|
625
|
-
const FunObjVar *
|
|
626
|
-
|
|
715
|
+
const FunObjVar *calleeFun =callNode->getCalledFunction();
|
|
716
|
+
if (Options::HandleRecur() == WIDEN_ONLY || Options::HandleRecur() == WIDEN_NARROW)
|
|
717
|
+
{
|
|
718
|
+
if (isRecursiveCallSite(callNode, calleeFun))
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
callSiteStack.push_back(callNode);
|
|
723
|
+
|
|
724
|
+
const ICFGWTO* wto = funcToWTO[calleeFun];
|
|
627
725
|
handleWTOComponents(wto->getWTOComponents());
|
|
628
726
|
|
|
629
727
|
callSiteStack.pop_back();
|
|
@@ -633,13 +731,13 @@ void AbstractInterpretation::directCallFunPass(const SVF::CallICFGNode *callNode
|
|
|
633
731
|
abstractTrace[retNode] = abstractTrace[callNode];
|
|
634
732
|
}
|
|
635
733
|
|
|
636
|
-
bool AbstractInterpretation::isIndirectCall(const
|
|
734
|
+
bool AbstractInterpretation::isIndirectCall(const CallICFGNode *callNode)
|
|
637
735
|
{
|
|
638
736
|
const auto callsiteMaps = svfir->getIndirectCallsites();
|
|
639
737
|
return callsiteMaps.find(callNode) != callsiteMaps.end();
|
|
640
738
|
}
|
|
641
739
|
|
|
642
|
-
void AbstractInterpretation::indirectCallFunPass(const
|
|
740
|
+
void AbstractInterpretation::indirectCallFunPass(const CallICFGNode *callNode)
|
|
643
741
|
{
|
|
644
742
|
AbstractState& as = getAbsStateFromTrace(callNode);
|
|
645
743
|
const auto callsiteMaps = svfir->getIndirectCallsites();
|
|
@@ -651,13 +749,20 @@ void AbstractInterpretation::indirectCallFunPass(const SVF::CallICFGNode *callNo
|
|
|
651
749
|
AbstractValue Addrs = as[call_id];
|
|
652
750
|
NodeID addr = *Addrs.getAddrs().begin();
|
|
653
751
|
SVFVar *func_var = svfir->getGNode(AbstractState::getInternalID(addr));
|
|
654
|
-
|
|
752
|
+
|
|
753
|
+
if(const FunObjVar* funObjVar = SVFUtil::dyn_cast<FunObjVar>(func_var))
|
|
655
754
|
{
|
|
755
|
+
if (Options::HandleRecur() == WIDEN_ONLY || Options::HandleRecur() == WIDEN_NARROW)
|
|
756
|
+
{
|
|
757
|
+
if (isRecursiveCallSite(callNode, funObjVar))
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
|
|
656
761
|
const FunObjVar* callfun = funObjVar->getFunction();
|
|
657
762
|
callSiteStack.push_back(callNode);
|
|
658
763
|
abstractTrace[callNode] = as;
|
|
659
764
|
|
|
660
|
-
ICFGWTO* wto = funcToWTO[callfun];
|
|
765
|
+
const ICFGWTO* wto = funcToWTO[callfun];
|
|
661
766
|
handleWTOComponents(wto->getWTOComponents());
|
|
662
767
|
callSiteStack.pop_back();
|
|
663
768
|
// handle Ret node
|
|
@@ -666,8 +771,6 @@ void AbstractInterpretation::indirectCallFunPass(const SVF::CallICFGNode *callNo
|
|
|
666
771
|
}
|
|
667
772
|
}
|
|
668
773
|
|
|
669
|
-
|
|
670
|
-
|
|
671
774
|
/// handle wto cycle (loop)
|
|
672
775
|
void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle)
|
|
673
776
|
{
|
|
@@ -686,8 +789,32 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle)
|
|
|
686
789
|
AbstractState cur_head_state = abstractTrace[cycle_head];
|
|
687
790
|
if (increasing)
|
|
688
791
|
{
|
|
689
|
-
// Widening
|
|
690
|
-
|
|
792
|
+
// Widening, use different modes for nodes within recursions
|
|
793
|
+
if (isRecursiveFun(cycle->head()->getICFGNode()->getFun()))
|
|
794
|
+
{
|
|
795
|
+
// For nodes in recursions, widen to top in WIDEN_TOP mode
|
|
796
|
+
if (Options::HandleRecur() == WIDEN_ONLY)
|
|
797
|
+
{
|
|
798
|
+
abstractTrace[cycle_head] = prev_head_state.widening(cur_head_state);
|
|
799
|
+
}
|
|
800
|
+
// Perform normal widening in WIDEN_NARROW mode
|
|
801
|
+
else if (Options::HandleRecur() == WIDEN_NARROW)
|
|
802
|
+
{
|
|
803
|
+
abstractTrace[cycle_head] = prev_head_state.widening(cur_head_state);
|
|
804
|
+
}
|
|
805
|
+
// In TOP mode, skipRecursiveCall will handle recursions,
|
|
806
|
+
// thus should not reach this branch
|
|
807
|
+
else
|
|
808
|
+
{
|
|
809
|
+
assert(false && "Recursion mode TOP should not reach here!");
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
// For nodes outside recursions, perform normal widening
|
|
813
|
+
else
|
|
814
|
+
{
|
|
815
|
+
abstractTrace[cycle_head] = prev_head_state.widening(cur_head_state);
|
|
816
|
+
}
|
|
817
|
+
|
|
691
818
|
if (abstractTrace[cycle_head] == prev_head_state)
|
|
692
819
|
{
|
|
693
820
|
increasing = false;
|
|
@@ -696,19 +823,49 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle)
|
|
|
696
823
|
}
|
|
697
824
|
else
|
|
698
825
|
{
|
|
699
|
-
//
|
|
700
|
-
|
|
701
|
-
if (abstractTrace[cycle_head] == prev_head_state)
|
|
826
|
+
// Narrowing, use different modes for nodes within recursions
|
|
827
|
+
if (isRecursiveFun(cycle->head()->getICFGNode()->getFun()))
|
|
702
828
|
{
|
|
703
|
-
//
|
|
704
|
-
|
|
829
|
+
// For nodes in recursions, skip narrowing in WIDEN_TOP mode
|
|
830
|
+
if (Options::HandleRecur() == WIDEN_ONLY)
|
|
831
|
+
{
|
|
832
|
+
break;
|
|
833
|
+
}
|
|
834
|
+
// Perform normal narrowing in WIDEN_NARROW mode
|
|
835
|
+
else if (Options::HandleRecur() == WIDEN_NARROW)
|
|
836
|
+
{
|
|
837
|
+
// Widening's fixpoint reached in the widening phase, switch to narrowing
|
|
838
|
+
abstractTrace[cycle_head] = prev_head_state.narrowing(cur_head_state);
|
|
839
|
+
if (abstractTrace[cycle_head] == prev_head_state)
|
|
840
|
+
{
|
|
841
|
+
// Narrowing's fixpoint reached in the narrowing phase, exit loop
|
|
842
|
+
break;
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
// In TOP mode, skipRecursiveCall will handle recursions,
|
|
846
|
+
// thus should not reach this branch
|
|
847
|
+
else
|
|
848
|
+
{
|
|
849
|
+
assert(false && "Recursion mode TOP should not reach here");
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
// For nodes outside recursions, perform normal narrowing
|
|
853
|
+
else
|
|
854
|
+
{
|
|
855
|
+
// Widening's fixpoint reached in the widening phase, switch to narrowing
|
|
856
|
+
abstractTrace[cycle_head] = prev_head_state.narrowing(cur_head_state);
|
|
857
|
+
if (abstractTrace[cycle_head] == prev_head_state)
|
|
858
|
+
{
|
|
859
|
+
// Narrowing's fixpoint reached in the narrowing phase, exit loop
|
|
860
|
+
break;
|
|
861
|
+
}
|
|
705
862
|
}
|
|
706
863
|
}
|
|
707
864
|
}
|
|
708
865
|
else
|
|
709
866
|
{
|
|
710
867
|
// Handle the cycle head
|
|
711
|
-
|
|
868
|
+
handleWTOComponent(cycle->head());
|
|
712
869
|
}
|
|
713
870
|
// Handle the cycle body
|
|
714
871
|
handleWTOComponents(cycle->getWTOComponents());
|
|
@@ -773,7 +930,6 @@ void AbstractInterpretation::handleSVFStatement(const SVFStmt *stmt)
|
|
|
773
930
|
assert(false && "implement this part");
|
|
774
931
|
}
|
|
775
932
|
|
|
776
|
-
|
|
777
933
|
void AbstractInterpretation::SkipRecursiveCall(const CallICFGNode *callNode)
|
|
778
934
|
{
|
|
779
935
|
AbstractState& as = getAbsStateFromTrace(callNode);
|
|
@@ -1212,10 +1368,8 @@ void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp)
|
|
|
1212
1368
|
resVal = IntervalValue(1, 1);
|
|
1213
1369
|
break;
|
|
1214
1370
|
default:
|
|
1215
|
-
{
|
|
1216
1371
|
assert(false && "undefined compare: ");
|
|
1217
1372
|
}
|
|
1218
|
-
}
|
|
1219
1373
|
as[res] = resVal;
|
|
1220
1374
|
}
|
|
1221
1375
|
else if (as[op0].isAddr() && as[op1].isAddr())
|
|
@@ -1328,10 +1482,8 @@ void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp)
|
|
|
1328
1482
|
resVal = IntervalValue(1, 1);
|
|
1329
1483
|
break;
|
|
1330
1484
|
default:
|
|
1331
|
-
{
|
|
1332
1485
|
assert(false && "undefined compare: ");
|
|
1333
1486
|
}
|
|
1334
|
-
}
|
|
1335
1487
|
as[res] = resVal;
|
|
1336
1488
|
}
|
|
1337
1489
|
}
|
|
@@ -1389,9 +1541,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy)
|
|
|
1389
1541
|
// we only support i64 at most
|
|
1390
1542
|
}
|
|
1391
1543
|
else
|
|
1392
|
-
{
|
|
1393
1544
|
assert(false && "cannot support int type other than u8/16/32/64");
|
|
1394
|
-
}
|
|
1395
1545
|
}
|
|
1396
1546
|
else
|
|
1397
1547
|
{
|
|
@@ -1401,7 +1551,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy)
|
|
|
1401
1551
|
return IntervalValue::top(); // TODO: may have better solution
|
|
1402
1552
|
};
|
|
1403
1553
|
|
|
1404
|
-
auto getTruncValue = [&](const AbstractState& as, const
|
|
1554
|
+
auto getTruncValue = [&](const AbstractState& as, const SVFVar* var,
|
|
1405
1555
|
const SVFType* dstType)
|
|
1406
1556
|
{
|
|
1407
1557
|
const IntervalValue& itv = as[var->getId()].getInterval();
|
|
@@ -1448,9 +1598,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy)
|
|
|
1448
1598
|
return IntervalValue(s32_lb, s32_ub);
|
|
1449
1599
|
}
|
|
1450
1600
|
else
|
|
1451
|
-
{
|
|
1452
1601
|
assert(false && "cannot support dst int type other than u8/16/32");
|
|
1453
|
-
}
|
|
1454
1602
|
};
|
|
1455
1603
|
|
|
1456
1604
|
AbstractState& as = getAbsStateFromTrace(copy->getICFGNode());
|
|
@@ -1513,10 +1661,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy)
|
|
|
1513
1661
|
}
|
|
1514
1662
|
}
|
|
1515
1663
|
else
|
|
1516
|
-
{
|
|
1517
1664
|
assert(false && "undefined copy kind");
|
|
1518
|
-
abort();
|
|
1519
|
-
}
|
|
1520
1665
|
}
|
|
1521
1666
|
|
|
1522
1667
|
|
package/svf/lib/Util/Options.cpp
CHANGED
|
@@ -779,6 +779,19 @@ const Option<u32_t> Options::LoopBound(
|
|
|
779
779
|
|
|
780
780
|
const Option<u32_t> Options::WidenDelay(
|
|
781
781
|
"widen-delay", "Loop Widen Delay", 3);
|
|
782
|
+
const OptionMap<AbstractInterpretation::HandleRecur> Options::HandleRecur(
|
|
783
|
+
"handle-recur",
|
|
784
|
+
"Recursion handling mode in abstract execution (Default -widen-narrow)",
|
|
785
|
+
AbstractInterpretation::HandleRecur::WIDEN_NARROW,
|
|
786
|
+
{
|
|
787
|
+
{AbstractInterpretation::HandleRecur::TOP, "top",
|
|
788
|
+
"The return value, and any stored object pointed by q at *q = p in recursive functions will be set to the top value."},
|
|
789
|
+
{AbstractInterpretation::HandleRecur::WIDEN_ONLY, "widen-only",
|
|
790
|
+
"Only apply widening at the cycle head of recursive functions."},
|
|
791
|
+
{AbstractInterpretation::HandleRecur::WIDEN_NARROW, "widen-narrow",
|
|
792
|
+
"Apply both widening and narrowing at the cycle head of recursive functions."}
|
|
793
|
+
}
|
|
794
|
+
);
|
|
782
795
|
const Option<u32_t> Options::Timeout(
|
|
783
796
|
"timeout", "time out (seconds), set -1 (no timeout), default 14400s",14400);
|
|
784
797
|
const Option<std::string> Options::OutputName(
|
package/svf-llvm/tools/AE/ae.cpp
CHANGED