svf-tools 1.0.972 → 1.0.974
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/AE/Core/AbstractState.h +18 -11
- package/svf/include/AE/Svfexe/AbstractInterpretation.h +40 -28
- package/svf/include/AE/Svfexe/BufOverflowChecker.h +17 -6
- package/svf/include/AE/Svfexe/ICFGSimplification.h +0 -1
- package/svf/include/Util/SVFBugReport.h +3 -3
- package/svf/lib/AE/Core/AbstractState.cpp +309 -54
- package/svf/lib/AE/Svfexe/AbstractInterpretation.cpp +740 -217
- package/svf/lib/AE/Svfexe/BufOverflowChecker.cpp +27 -37
- package/svf/lib/AE/Svfexe/ICFGSimplification.cpp +1 -0
- package/svf-llvm/tools/AE/ae.cpp +15 -1
- package/svf-llvm/tools/Example/svf-ex.cpp +1 -66
- package/svf/include/AE/Svfexe/SVFIR2AbsState.h +0 -191
- package/svf/lib/AE/Svfexe/SVFIR2AbsState.cpp +0 -957
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svf-tools",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.974",
|
|
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": {
|
|
@@ -46,8 +46,9 @@
|
|
|
46
46
|
#ifndef Z3_EXAMPLE_INTERVAL_DOMAIN_H
|
|
47
47
|
#define Z3_EXAMPLE_INTERVAL_DOMAIN_H
|
|
48
48
|
|
|
49
|
-
#include "AE/Core/IntervalValue.h"
|
|
50
49
|
#include "AE/Core/AbstractValue.h"
|
|
50
|
+
#include "AE/Core/IntervalValue.h"
|
|
51
|
+
#include "SVFIR/SVFVariables.h"
|
|
51
52
|
#include "Util/Z3Expr.h"
|
|
52
53
|
|
|
53
54
|
#include <iomanip>
|
|
@@ -79,6 +80,21 @@ public:
|
|
|
79
80
|
|
|
80
81
|
virtual ~AbstractState() = default;
|
|
81
82
|
|
|
83
|
+
// getGepObjAddrs
|
|
84
|
+
AddressValue getGepObjAddrs(u32_t pointer, IntervalValue offset);
|
|
85
|
+
|
|
86
|
+
// initObjVar
|
|
87
|
+
void initObjVar(ObjVar* objVar);
|
|
88
|
+
// getElementIndex
|
|
89
|
+
IntervalValue getElementIndex(const GepStmt* gep);
|
|
90
|
+
// getByteOffset
|
|
91
|
+
IntervalValue getByteOffset(const GepStmt* gep);
|
|
92
|
+
// printAbstractState
|
|
93
|
+
// loadValue
|
|
94
|
+
AbstractValue loadValue(NodeID varId);
|
|
95
|
+
// storeValue
|
|
96
|
+
void storeValue(NodeID varId, AbstractValue val);
|
|
97
|
+
|
|
82
98
|
|
|
83
99
|
/// The physical address starts with 0x7f...... + idx
|
|
84
100
|
static inline u32_t getVirtualMemAddress(u32_t idx)
|
|
@@ -258,14 +274,9 @@ public:
|
|
|
258
274
|
/// domain narrow with other, and return the narrowed domain
|
|
259
275
|
AbstractState narrowing(const AbstractState&other);
|
|
260
276
|
|
|
261
|
-
/// domain widen with other, important! other widen this.
|
|
262
|
-
void widenWith(const AbstractState&other);
|
|
263
|
-
|
|
264
277
|
/// domain join with other, important! other widen this.
|
|
265
278
|
void joinWith(const AbstractState&other);
|
|
266
279
|
|
|
267
|
-
/// domain narrow with other, important! other widen this.
|
|
268
|
-
void narrowWith(const AbstractState&other);
|
|
269
280
|
|
|
270
281
|
/// domain meet with other, important! other widen this.
|
|
271
282
|
void meetWith(const AbstractState&other);
|
|
@@ -299,8 +310,7 @@ public:
|
|
|
299
310
|
}
|
|
300
311
|
|
|
301
312
|
|
|
302
|
-
|
|
303
|
-
void printExprValues(std::ostream &oss) const;
|
|
313
|
+
void printAbstractState() const;
|
|
304
314
|
|
|
305
315
|
std::string toString() const
|
|
306
316
|
{
|
|
@@ -386,9 +396,6 @@ public:
|
|
|
386
396
|
}
|
|
387
397
|
|
|
388
398
|
|
|
389
|
-
protected:
|
|
390
|
-
void printTable(const VarToAbsValMap&table, std::ostream &oss) const;
|
|
391
|
-
|
|
392
399
|
};
|
|
393
400
|
|
|
394
401
|
}
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
//
|
|
30
30
|
|
|
31
31
|
#include "AE/Core/ICFGWTO.h"
|
|
32
|
-
#include "AE/Svfexe/SVFIR2AbsState.h"
|
|
33
32
|
#include "Util/SVFBugReport.h"
|
|
34
33
|
#include "WPA/Andersen.h"
|
|
34
|
+
#include "AE/Core/AbstractState.h"
|
|
35
35
|
|
|
36
36
|
namespace SVF
|
|
37
37
|
{
|
|
@@ -137,8 +137,8 @@ protected:
|
|
|
137
137
|
/// Global ICFGNode is handled at the entry of the program,
|
|
138
138
|
virtual void handleGlobalNode();
|
|
139
139
|
|
|
140
|
-
///
|
|
141
|
-
void
|
|
140
|
+
/// Mark recursive functions in the call graph
|
|
141
|
+
void initWTO();
|
|
142
142
|
|
|
143
143
|
/**
|
|
144
144
|
* Check if execution state exist by merging states of predecessor nodes
|
|
@@ -146,7 +146,7 @@ protected:
|
|
|
146
146
|
* @param curNode The ICFGNode to analyse
|
|
147
147
|
* @return if this node has preceding execution state
|
|
148
148
|
*/
|
|
149
|
-
bool
|
|
149
|
+
bool mergeStatesFromPredecessors(const ICFGNode* curNode);
|
|
150
150
|
|
|
151
151
|
/**
|
|
152
152
|
* Check if execution state exist at the branch edge
|
|
@@ -161,14 +161,7 @@ protected:
|
|
|
161
161
|
*
|
|
162
162
|
* @param block basic block that has one instruction or a series of instructions
|
|
163
163
|
*/
|
|
164
|
-
virtual void
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* handle one instruction in ICFGNode
|
|
168
|
-
*
|
|
169
|
-
* @param node ICFGNode which has a single instruction
|
|
170
|
-
*/
|
|
171
|
-
virtual void handleICFGNode(const ICFGNode* node);
|
|
164
|
+
virtual void handleSingletonWTO(const ICFGSingletonWTO *icfgSingletonWto);
|
|
172
165
|
|
|
173
166
|
/**
|
|
174
167
|
* handle call node in ICFGNode
|
|
@@ -182,14 +175,10 @@ protected:
|
|
|
182
175
|
*
|
|
183
176
|
* @param cycle WTOCycle which has weak topo order of basic blocks and nested cycles
|
|
184
177
|
*/
|
|
185
|
-
virtual void
|
|
178
|
+
virtual void handleCycleWTO(const ICFGCycleWTO* cycle);
|
|
179
|
+
|
|
180
|
+
void handleWTOComponents(const std::list<const ICFGWTOComp*>& wtoComps);
|
|
186
181
|
|
|
187
|
-
/**
|
|
188
|
-
* handle user defined function, ext function is not included.
|
|
189
|
-
*
|
|
190
|
-
* @param func SVFFunction which has a series of basic blocks
|
|
191
|
-
*/
|
|
192
|
-
virtual void handleFunc(const SVFFunction* func);
|
|
193
182
|
|
|
194
183
|
/**
|
|
195
184
|
* handle SVF Statement like CmpStmt, CallStmt, GepStmt, LoadStmt, StoreStmt, etc.
|
|
@@ -332,11 +321,34 @@ protected:
|
|
|
332
321
|
void AccessMemoryViaCallArgs(const SVF::SVFArgument *arg, SVF::FILOWorkList<const SVFValue *>& worklist, Set<const SVFValue *>& visited);
|
|
333
322
|
|
|
334
323
|
|
|
324
|
+
void updateStateOnAddr(const AddrStmt *addr);
|
|
325
|
+
|
|
326
|
+
void updateStateOnBinary(const BinaryOPStmt *binary);
|
|
327
|
+
|
|
328
|
+
void updateStateOnCmp(const CmpStmt *cmp);
|
|
329
|
+
|
|
330
|
+
void updateStateOnLoad(const LoadStmt *load);
|
|
331
|
+
|
|
332
|
+
void updateStateOnStore(const StoreStmt *store);
|
|
333
|
+
|
|
334
|
+
void updateStateOnCopy(const CopyStmt *copy);
|
|
335
|
+
|
|
336
|
+
void updateStateOnCall(const CallPE *callPE);
|
|
337
|
+
|
|
338
|
+
void updateStateOnRet(const RetPE *retPE);
|
|
339
|
+
|
|
340
|
+
void updateStateOnGep(const GepStmt *gep);
|
|
341
|
+
|
|
342
|
+
void updateStateOnSelect(const SelectStmt *select);
|
|
343
|
+
|
|
344
|
+
void updateStateOnPhi(const PhiStmt *phi);
|
|
345
|
+
|
|
346
|
+
IntervalValue getRangeLimitFromType(const SVFType* type);
|
|
347
|
+
|
|
348
|
+
|
|
335
349
|
/// protected data members, also used in subclasses
|
|
336
350
|
SVFIR* _svfir;
|
|
337
|
-
PTACallGraph* _callgraph;
|
|
338
351
|
/// Execution State, used to store the Interval Value of every SVF variable
|
|
339
|
-
SVFIR2AbsState* _svfir2AbsState;
|
|
340
352
|
AEAPI* _api{nullptr};
|
|
341
353
|
|
|
342
354
|
ICFG* _icfg;
|
|
@@ -347,7 +359,6 @@ protected:
|
|
|
347
359
|
SVFBugReport _recoder;
|
|
348
360
|
std::vector<const CallICFGNode*> _callSiteStack;
|
|
349
361
|
Map<const ICFGNode*, std::string> _nodeToBugInfo;
|
|
350
|
-
AndersenWaveDiff* _ander;
|
|
351
362
|
Map<const SVFFunction*, ICFGWTO*> _funcToWTO;
|
|
352
363
|
Set<const SVFFunction*> _recursiveFuns;
|
|
353
364
|
|
|
@@ -363,13 +374,8 @@ private:
|
|
|
363
374
|
virtual void indirectCallFunPass(const CallICFGNode* callNode);
|
|
364
375
|
|
|
365
376
|
protected:
|
|
366
|
-
// helper functions in handleCycle
|
|
367
|
-
bool isFixPointAfterWidening(const ICFGNode* cycle_head,
|
|
368
|
-
AbstractState& pre_as);
|
|
369
|
-
bool isFixPointAfterNarrowing(const SVF::ICFGNode* cycle_head,
|
|
370
|
-
SVF::AbstractState& pre_as);
|
|
371
377
|
|
|
372
|
-
AbstractState&
|
|
378
|
+
AbstractState& getAbsStateFromTrace(const ICFGNode* node)
|
|
373
379
|
{
|
|
374
380
|
const ICFGNode* repNode = _icfg->getRepNode(node);
|
|
375
381
|
if (_postAbsTrace.count(repNode) == 0)
|
|
@@ -382,6 +388,12 @@ protected:
|
|
|
382
388
|
}
|
|
383
389
|
}
|
|
384
390
|
|
|
391
|
+
bool hasAbsStateFromTrace(const ICFGNode* node)
|
|
392
|
+
{
|
|
393
|
+
const ICFGNode* repNode = _icfg->getRepNode(node);
|
|
394
|
+
return _postAbsTrace.count(repNode) != 0;
|
|
395
|
+
}
|
|
396
|
+
|
|
385
397
|
protected:
|
|
386
398
|
// there data should be shared with subclasses
|
|
387
399
|
Map<std::string, std::function<void(const CallSite &)>> _func_map;
|
|
@@ -174,12 +174,23 @@ private:
|
|
|
174
174
|
*/
|
|
175
175
|
virtual void handleSVFStatement(const SVFStmt *stmt) override;
|
|
176
176
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
// TODO: will delete later
|
|
178
|
+
virtual void handleSingletonWTO(const ICFGSingletonWTO *icfgSingletonWto) override
|
|
179
|
+
{
|
|
180
|
+
AbstractInterpretation::handleSingletonWTO(icfgSingletonWto);
|
|
181
|
+
const ICFGNode* repNode = _icfg->getRepNode(icfgSingletonWto->node());
|
|
182
|
+
if (_postAbsTrace.count(repNode) == 0)
|
|
183
|
+
{
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const std::vector<const ICFGNode*>& worklist_vec = _icfg->getSubNodes(icfgSingletonWto->node());
|
|
187
|
+
|
|
188
|
+
for (auto it = worklist_vec.begin(); it != worklist_vec.end(); ++it)
|
|
189
|
+
{
|
|
190
|
+
const ICFGNode* curNode = *it;
|
|
191
|
+
detectBufOverflow(curNode);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
183
194
|
|
|
184
195
|
/**
|
|
185
196
|
* check buffer overflow at ICFGNode which is a checkpoint
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
// The implementation is based on
|
|
28
28
|
// Xiao Cheng, Jiawei Wang and Yulei Sui. Precise Sparse Abstract Execution via Cross-Domain Interaction.
|
|
29
29
|
// 46th International Conference on Software Engineering. (ICSE24)
|
|
30
|
-
#include "AE/Svfexe/SVFIR2AbsState.h"
|
|
31
30
|
#include "Graphs/ICFG.h"
|
|
32
31
|
|
|
33
32
|
namespace SVF
|
|
@@ -209,7 +209,7 @@ class DoubleFreeBug : public GenericBug
|
|
|
209
209
|
{
|
|
210
210
|
public:
|
|
211
211
|
DoubleFreeBug(const EventStack &bugEventStack):
|
|
212
|
-
GenericBug(GenericBug::
|
|
212
|
+
GenericBug(GenericBug::DOUBLEFREE, bugEventStack) { }
|
|
213
213
|
|
|
214
214
|
cJSON *getBugDescription() const;
|
|
215
215
|
void printBugToTerminal() const;
|
|
@@ -225,7 +225,7 @@ class FileNeverCloseBug : public GenericBug
|
|
|
225
225
|
{
|
|
226
226
|
public:
|
|
227
227
|
FileNeverCloseBug(const EventStack &bugEventStack):
|
|
228
|
-
GenericBug(GenericBug::
|
|
228
|
+
GenericBug(GenericBug::FILENEVERCLOSE, bugEventStack) { };
|
|
229
229
|
|
|
230
230
|
cJSON *getBugDescription() const;
|
|
231
231
|
void printBugToTerminal() const;
|
|
@@ -241,7 +241,7 @@ class FilePartialCloseBug : public GenericBug
|
|
|
241
241
|
{
|
|
242
242
|
public:
|
|
243
243
|
FilePartialCloseBug(const EventStack &bugEventStack):
|
|
244
|
-
GenericBug(GenericBug::
|
|
244
|
+
GenericBug(GenericBug::FILEPARTIALCLOSE, bugEventStack) { }
|
|
245
245
|
|
|
246
246
|
cJSON *getBugDescription() const;
|
|
247
247
|
void printBugToTerminal() const;
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
#include "AE/Core/AbstractState.h"
|
|
31
31
|
#include "Util/SVFUtil.h"
|
|
32
|
+
#include "Util/Options.h"
|
|
32
33
|
|
|
33
34
|
using namespace SVF;
|
|
34
35
|
using namespace SVFUtil;
|
|
@@ -97,25 +98,6 @@ AbstractState AbstractState::narrowing(const AbstractState& other)
|
|
|
97
98
|
|
|
98
99
|
}
|
|
99
100
|
|
|
100
|
-
/// domain widen with other, important! other widen this.
|
|
101
|
-
void AbstractState::widenWith(const AbstractState& other)
|
|
102
|
-
{
|
|
103
|
-
for (auto it = _varToAbsVal.begin(); it != _varToAbsVal.end(); ++it)
|
|
104
|
-
{
|
|
105
|
-
auto key = it->first;
|
|
106
|
-
if (other.getVarToVal().find(key) != other.getVarToVal().end())
|
|
107
|
-
if (it->second.isInterval() && other._varToAbsVal.at(key).isInterval())
|
|
108
|
-
it->second.getInterval().widen_with(other._varToAbsVal.at(key).getInterval());
|
|
109
|
-
}
|
|
110
|
-
for (auto it = _addrToAbsVal.begin(); it != _addrToAbsVal.end(); ++it)
|
|
111
|
-
{
|
|
112
|
-
auto key = it->first;
|
|
113
|
-
if (other._addrToAbsVal.find(key) != other._addrToAbsVal.end())
|
|
114
|
-
if (it->second.isInterval() && other._varToAbsVal.at(key).isInterval())
|
|
115
|
-
it->second.getInterval().widen_with(other._addrToAbsVal.at(key).getInterval());
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
101
|
/// domain join with other, important! other widen this.
|
|
120
102
|
void AbstractState::joinWith(const AbstractState& other)
|
|
121
103
|
{
|
|
@@ -147,27 +129,6 @@ void AbstractState::joinWith(const AbstractState& other)
|
|
|
147
129
|
}
|
|
148
130
|
}
|
|
149
131
|
|
|
150
|
-
/// domain narrow with other, important! other widen this.
|
|
151
|
-
void AbstractState::narrowWith(const AbstractState& other)
|
|
152
|
-
{
|
|
153
|
-
for (auto it = _varToAbsVal.begin(); it != _varToAbsVal.end(); ++it)
|
|
154
|
-
{
|
|
155
|
-
auto key = it->first;
|
|
156
|
-
auto oit = other.getVarToVal().find(key);
|
|
157
|
-
if (oit != other.getVarToVal().end())
|
|
158
|
-
if (it->second.isInterval() && oit->second.isInterval())
|
|
159
|
-
it->second.getInterval().narrow_with(oit->second.getInterval());
|
|
160
|
-
}
|
|
161
|
-
for (auto it = _addrToAbsVal.begin(); it != _addrToAbsVal.end(); ++it)
|
|
162
|
-
{
|
|
163
|
-
auto key = it->first;
|
|
164
|
-
auto oit = other._addrToAbsVal.find(key);
|
|
165
|
-
if (oit != other._addrToAbsVal.end())
|
|
166
|
-
if (it->second.isInterval() && oit->second.isInterval())
|
|
167
|
-
it->second.getInterval().narrow_with(oit->second.getInterval());
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
132
|
/// domain meet with other, important! other widen this.
|
|
172
133
|
void AbstractState::meetWith(const AbstractState& other)
|
|
173
134
|
{
|
|
@@ -191,26 +152,320 @@ void AbstractState::meetWith(const AbstractState& other)
|
|
|
191
152
|
}
|
|
192
153
|
}
|
|
193
154
|
|
|
194
|
-
|
|
195
|
-
|
|
155
|
+
// getGepObjAddrs
|
|
156
|
+
AddressValue AbstractState::getGepObjAddrs(u32_t pointer, IntervalValue offset)
|
|
157
|
+
{
|
|
158
|
+
AddressValue gepAddrs;
|
|
159
|
+
APOffset lb = offset.lb().getIntNumeral() < Options::MaxFieldLimit() ? offset.lb().getIntNumeral()
|
|
160
|
+
: Options::MaxFieldLimit();
|
|
161
|
+
APOffset ub = offset.ub().getIntNumeral() < Options::MaxFieldLimit() ? offset.ub().getIntNumeral()
|
|
162
|
+
: Options::MaxFieldLimit();
|
|
163
|
+
for (APOffset i = lb; i <= ub; i++)
|
|
164
|
+
{
|
|
165
|
+
AbstractValue addrs = (*this)[pointer];
|
|
166
|
+
for (const auto& addr : addrs.getAddrs())
|
|
167
|
+
{
|
|
168
|
+
s64_t baseObj = AbstractState::getInternalID(addr);
|
|
169
|
+
assert(SVFUtil::isa<ObjVar>(PAG::getPAG()->getGNode(baseObj)) && "Fail to get the base object address!");
|
|
170
|
+
NodeID gepObj = PAG::getPAG()->getGepObjVar(baseObj, i);
|
|
171
|
+
(*this)[gepObj] = AddressValue(AbstractState::getVirtualMemAddress(gepObj));
|
|
172
|
+
gepAddrs.insert(AbstractState::getVirtualMemAddress(gepObj));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return gepAddrs;
|
|
177
|
+
}
|
|
178
|
+
// initObjVar
|
|
179
|
+
void AbstractState::initObjVar(ObjVar* objVar)
|
|
180
|
+
{
|
|
181
|
+
NodeID varId = objVar->getId();
|
|
182
|
+
|
|
183
|
+
// Check if the object variable has an associated value
|
|
184
|
+
if (objVar->hasValue())
|
|
185
|
+
{
|
|
186
|
+
const MemObj* obj = objVar->getMemObj();
|
|
187
|
+
|
|
188
|
+
// Handle constant data, arrays, and structures
|
|
189
|
+
if (obj->isConstDataOrConstGlobal() || obj->isConstantArray() || obj->isConstantStruct())
|
|
190
|
+
{
|
|
191
|
+
if (const SVFConstantInt* consInt = SVFUtil::dyn_cast<SVFConstantInt>(obj->getValue()))
|
|
192
|
+
{
|
|
193
|
+
s64_t numeral = consInt->getSExtValue();
|
|
194
|
+
(*this)[varId] = IntervalValue(numeral, numeral);
|
|
195
|
+
}
|
|
196
|
+
else if (const SVFConstantFP* consFP = SVFUtil::dyn_cast<SVFConstantFP>(obj->getValue()))
|
|
197
|
+
{
|
|
198
|
+
(*this)[varId] = IntervalValue(consFP->getFPValue(), consFP->getFPValue());
|
|
199
|
+
}
|
|
200
|
+
else if (SVFUtil::isa<SVFConstantNullPtr>(obj->getValue()))
|
|
201
|
+
{
|
|
202
|
+
(*this)[varId] = IntervalValue(0, 0);
|
|
203
|
+
}
|
|
204
|
+
else if (SVFUtil::isa<SVFGlobalValue>(obj->getValue()))
|
|
205
|
+
{
|
|
206
|
+
(*this)[varId] = AddressValue(AbstractState::getVirtualMemAddress(varId));
|
|
207
|
+
}
|
|
208
|
+
else if (obj->isConstantArray() || obj->isConstantStruct())
|
|
209
|
+
{
|
|
210
|
+
(*this)[varId] = IntervalValue::top();
|
|
211
|
+
}
|
|
212
|
+
else
|
|
213
|
+
{
|
|
214
|
+
(*this)[varId] = IntervalValue::top();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Handle non-constant memory objects
|
|
218
|
+
else
|
|
219
|
+
{
|
|
220
|
+
(*this)[varId] = AddressValue(AbstractState::getVirtualMemAddress(varId));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// If the object variable does not have an associated value, set it to a virtual memory address
|
|
224
|
+
else
|
|
225
|
+
{
|
|
226
|
+
(*this)[varId] = AddressValue(AbstractState::getVirtualMemAddress(varId));
|
|
227
|
+
}
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// getElementIndex
|
|
232
|
+
IntervalValue AbstractState::getElementIndex(const GepStmt* gep)
|
|
233
|
+
{
|
|
234
|
+
// If the GEP statement has a constant offset, return it directly as the interval value
|
|
235
|
+
if (gep->isConstantOffset())
|
|
236
|
+
return IntervalValue((s64_t)gep->accumulateConstantOffset());
|
|
237
|
+
|
|
238
|
+
IntervalValue res(0);
|
|
239
|
+
// Iterate over the list of offset variable and type pairs in reverse order
|
|
240
|
+
for (int i = gep->getOffsetVarAndGepTypePairVec().size() - 1; i >= 0; i--)
|
|
241
|
+
{
|
|
242
|
+
AccessPath::IdxOperandPair IdxVarAndType = gep->getOffsetVarAndGepTypePairVec()[i];
|
|
243
|
+
const SVFValue* value = gep->getOffsetVarAndGepTypePairVec()[i].first->getValue();
|
|
244
|
+
const SVFType* type = IdxVarAndType.second;
|
|
245
|
+
|
|
246
|
+
// Variables to store the lower and upper bounds of the index value
|
|
247
|
+
s64_t idxLb;
|
|
248
|
+
s64_t idxUb;
|
|
249
|
+
|
|
250
|
+
// Determine the lower and upper bounds based on whether the value is a constant
|
|
251
|
+
if (const SVFConstantInt* constInt = SVFUtil::dyn_cast<SVFConstantInt>(value))
|
|
252
|
+
idxLb = idxUb = constInt->getSExtValue();
|
|
253
|
+
else
|
|
254
|
+
{
|
|
255
|
+
IntervalValue idxItv = (*this)[PAG::getPAG()->getValueNode(value)].getInterval();
|
|
256
|
+
if (idxItv.isBottom())
|
|
257
|
+
idxLb = idxUb = 0;
|
|
258
|
+
else
|
|
259
|
+
{
|
|
260
|
+
idxLb = idxItv.lb().getIntNumeral();
|
|
261
|
+
idxUb = idxItv.ub().getIntNumeral();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Adjust the bounds if the type is a pointer
|
|
266
|
+
if (SVFUtil::isa<SVFPointerType>(type))
|
|
267
|
+
{
|
|
268
|
+
u32_t elemNum = gep->getAccessPath().getElementNum(gep->getAccessPath().gepSrcPointeeType());
|
|
269
|
+
idxLb = (double)Options::MaxFieldLimit() / elemNum < idxLb ? Options::MaxFieldLimit() : idxLb * elemNum;
|
|
270
|
+
idxUb = (double)Options::MaxFieldLimit() / elemNum < idxUb ? Options::MaxFieldLimit() : idxUb * elemNum;
|
|
271
|
+
}
|
|
272
|
+
// Adjust the bounds for array or struct types using the symbol table info
|
|
273
|
+
else
|
|
274
|
+
{
|
|
275
|
+
if (Options::ModelArrays())
|
|
276
|
+
{
|
|
277
|
+
const std::vector<u32_t>& so = SymbolTableInfo::SymbolInfo()->getTypeInfo(type)->getFlattenedElemIdxVec();
|
|
278
|
+
if (so.empty() || idxUb >= (APOffset)so.size() || idxLb < 0)
|
|
279
|
+
{
|
|
280
|
+
idxLb = idxUb = 0;
|
|
281
|
+
}
|
|
282
|
+
else
|
|
283
|
+
{
|
|
284
|
+
idxLb = SymbolTableInfo::SymbolInfo()->getFlattenedElemIdx(type, idxLb);
|
|
285
|
+
idxUb = SymbolTableInfo::SymbolInfo()->getFlattenedElemIdx(type, idxUb);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
else
|
|
289
|
+
idxLb = idxUb = 0;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Add the calculated interval to the result
|
|
293
|
+
res = res + IntervalValue(idxLb, idxUb);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Ensure the result is within the bounds of [0, MaxFieldLimit]
|
|
297
|
+
res.meet_with(IntervalValue((s64_t)0, (s64_t)Options::MaxFieldLimit()));
|
|
298
|
+
if (res.isBottom())
|
|
299
|
+
{
|
|
300
|
+
res = IntervalValue(0);
|
|
301
|
+
}
|
|
302
|
+
return res;
|
|
303
|
+
}
|
|
304
|
+
// getByteOffset
|
|
305
|
+
IntervalValue AbstractState::getByteOffset(const GepStmt* gep)
|
|
196
306
|
{
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
307
|
+
// If the GEP statement has a constant byte offset, return it directly as the interval value
|
|
308
|
+
if (gep->isConstantOffset())
|
|
309
|
+
return IntervalValue((s64_t)gep->accumulateConstantByteOffset());
|
|
310
|
+
|
|
311
|
+
IntervalValue res(0); // Initialize the result interval 'res' to 0.
|
|
312
|
+
|
|
313
|
+
// Loop through the offsetVarAndGepTypePairVec in reverse order.
|
|
314
|
+
for (int i = gep->getOffsetVarAndGepTypePairVec().size() - 1; i >= 0; i--)
|
|
315
|
+
{
|
|
316
|
+
const SVFVar* idxOperandVar = gep->getOffsetVarAndGepTypePairVec()[i].first;
|
|
317
|
+
const SVFType* idxOperandType = gep->getOffsetVarAndGepTypePairVec()[i].second;
|
|
318
|
+
|
|
319
|
+
// Calculate the byte offset for array or pointer types
|
|
320
|
+
if (SVFUtil::isa<SVFArrayType>(idxOperandType) || SVFUtil::isa<SVFPointerType>(idxOperandType))
|
|
321
|
+
{
|
|
322
|
+
u32_t elemByteSize = 1;
|
|
323
|
+
if (const SVFArrayType* arrOperandType = SVFUtil::dyn_cast<SVFArrayType>(idxOperandType))
|
|
324
|
+
elemByteSize = arrOperandType->getTypeOfElement()->getByteSize();
|
|
325
|
+
else if (SVFUtil::isa<SVFPointerType>(idxOperandType))
|
|
326
|
+
elemByteSize = gep->getAccessPath().gepSrcPointeeType()->getByteSize();
|
|
327
|
+
else
|
|
328
|
+
assert(false && "idxOperandType must be ArrType or PtrType");
|
|
329
|
+
|
|
330
|
+
if (const SVFConstantInt* op = SVFUtil::dyn_cast<SVFConstantInt>(idxOperandVar->getValue()))
|
|
331
|
+
{
|
|
332
|
+
// Calculate the lower bound (lb) of the interval value
|
|
333
|
+
s64_t lb = (double)Options::MaxFieldLimit() / elemByteSize >= op->getSExtValue()
|
|
334
|
+
? op->getSExtValue() * elemByteSize
|
|
335
|
+
: Options::MaxFieldLimit();
|
|
336
|
+
res = res + IntervalValue(lb, lb);
|
|
337
|
+
}
|
|
338
|
+
else
|
|
339
|
+
{
|
|
340
|
+
u32_t idx = PAG::getPAG()->getValueNode(idxOperandVar->getValue());
|
|
341
|
+
IntervalValue idxVal = (*this)[idx].getInterval();
|
|
342
|
+
|
|
343
|
+
if (idxVal.isBottom())
|
|
344
|
+
res = res + IntervalValue(0, 0);
|
|
345
|
+
else
|
|
346
|
+
{
|
|
347
|
+
// Ensure the bounds are non-negative and within the field limit
|
|
348
|
+
s64_t ub = (idxVal.ub().getIntNumeral() < 0) ? 0
|
|
349
|
+
: (double)Options::MaxFieldLimit() / elemByteSize >= idxVal.ub().getIntNumeral()
|
|
350
|
+
? elemByteSize * idxVal.ub().getIntNumeral()
|
|
351
|
+
: Options::MaxFieldLimit();
|
|
352
|
+
s64_t lb = (idxVal.lb().getIntNumeral() < 0) ? 0
|
|
353
|
+
: (double)Options::MaxFieldLimit() / elemByteSize >= idxVal.lb().getIntNumeral()
|
|
354
|
+
? elemByteSize * idxVal.lb().getIntNumeral()
|
|
355
|
+
: Options::MaxFieldLimit();
|
|
356
|
+
res = res + IntervalValue(lb, ub);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
// Process struct subtypes by calculating the byte offset from the beginning to the field of the struct
|
|
361
|
+
else if (const SVFStructType* structOperandType = SVFUtil::dyn_cast<SVFStructType>(idxOperandType))
|
|
362
|
+
{
|
|
363
|
+
res = res + IntervalValue(gep->getAccessPath().getStructFieldOffset(idxOperandVar, structOperandType));
|
|
364
|
+
}
|
|
365
|
+
else
|
|
366
|
+
{
|
|
367
|
+
assert(false && "gep type pair only support arr/ptr/struct");
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return res; // Return the resulting byte offset as an IntervalValue.
|
|
201
371
|
}
|
|
202
372
|
|
|
203
|
-
|
|
373
|
+
AbstractValue AbstractState::loadValue(NodeID varId)
|
|
204
374
|
{
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
for (const auto &item: table)
|
|
375
|
+
AbstractValue res;
|
|
376
|
+
for (auto addr : (*this)[varId].getAddrs())
|
|
208
377
|
{
|
|
209
|
-
|
|
378
|
+
res.join_with(load(addr)); // q = *p
|
|
210
379
|
}
|
|
211
|
-
|
|
380
|
+
return res;
|
|
381
|
+
}
|
|
382
|
+
// storeValue
|
|
383
|
+
void AbstractState::storeValue(NodeID varId, AbstractValue val)
|
|
384
|
+
{
|
|
385
|
+
for (auto addr : (*this)[varId].getAddrs())
|
|
212
386
|
{
|
|
213
|
-
|
|
214
|
-
oss << "\t Value: " << table.at(item).toString() << "\n";
|
|
387
|
+
store(addr, val); // *p = q
|
|
215
388
|
}
|
|
216
389
|
}
|
|
390
|
+
|
|
391
|
+
void AbstractState::printAbstractState() const
|
|
392
|
+
{
|
|
393
|
+
SVFUtil::outs() << "-----------Var and Value-----------\n";
|
|
394
|
+
u32_t fieldWidth = 20;
|
|
395
|
+
SVFUtil::outs().flags(std::ios::left);
|
|
396
|
+
std::vector<std::pair<u32_t, AbstractValue>> varToAbsValVec(_varToAbsVal.begin(), _varToAbsVal.end());
|
|
397
|
+
std::sort(varToAbsValVec.begin(), varToAbsValVec.end(), [](const auto &a, const auto &b)
|
|
398
|
+
{
|
|
399
|
+
return a.first < b.first;
|
|
400
|
+
});
|
|
401
|
+
for (const auto &item: varToAbsValVec)
|
|
402
|
+
{
|
|
403
|
+
SVFUtil::outs() << std::left << std::setw(fieldWidth) << ("Var" + std::to_string(item.first));
|
|
404
|
+
if (item.second.isInterval())
|
|
405
|
+
{
|
|
406
|
+
SVFUtil::outs() << " Value: " << item.second.getInterval().toString() << "\n";
|
|
407
|
+
}
|
|
408
|
+
else if (item.second.isAddr())
|
|
409
|
+
{
|
|
410
|
+
SVFUtil::outs() << " Value: {";
|
|
411
|
+
u32_t i = 0;
|
|
412
|
+
for (const auto& addr: item.second.getAddrs())
|
|
413
|
+
{
|
|
414
|
+
++i;
|
|
415
|
+
if (i < item.second.getAddrs().size())
|
|
416
|
+
{
|
|
417
|
+
SVFUtil::outs() << "0x" << std::hex << addr << ", ";
|
|
418
|
+
}
|
|
419
|
+
else
|
|
420
|
+
{
|
|
421
|
+
SVFUtil::outs() << "0x" << std::hex << addr;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
SVFUtil::outs() << "}\n";
|
|
425
|
+
}
|
|
426
|
+
else
|
|
427
|
+
{
|
|
428
|
+
SVFUtil::outs() << " Value: ⊥\n";
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
std::vector<std::pair<u32_t, AbstractValue>> addrToAbsValVec(_addrToAbsVal.begin(), _addrToAbsVal.end());
|
|
433
|
+
std::sort(addrToAbsValVec.begin(), addrToAbsValVec.end(), [](const auto &a, const auto &b)
|
|
434
|
+
{
|
|
435
|
+
return a.first < b.first;
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
for (const auto& item: addrToAbsValVec)
|
|
439
|
+
{
|
|
440
|
+
std::ostringstream oss;
|
|
441
|
+
oss << "0x" << std::hex << AbstractState::getVirtualMemAddress(item.first);
|
|
442
|
+
SVFUtil::outs() << std::left << std::setw(fieldWidth) << oss.str();
|
|
443
|
+
if (item.second.isInterval())
|
|
444
|
+
{
|
|
445
|
+
SVFUtil::outs() << " Value: " << item.second.getInterval().toString() << "\n";
|
|
446
|
+
}
|
|
447
|
+
else if (item.second.isAddr())
|
|
448
|
+
{
|
|
449
|
+
SVFUtil::outs() << " Value: {";
|
|
450
|
+
u32_t i = 0;
|
|
451
|
+
for (const auto& addr: item.second.getAddrs())
|
|
452
|
+
{
|
|
453
|
+
++i;
|
|
454
|
+
if (i < item.second.getAddrs().size())
|
|
455
|
+
{
|
|
456
|
+
SVFUtil::outs() << "0x" << std::hex << addr << ", ";
|
|
457
|
+
}
|
|
458
|
+
else
|
|
459
|
+
{
|
|
460
|
+
SVFUtil::outs() << "0x" << std::hex << addr;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
SVFUtil::outs() << "}\n";
|
|
464
|
+
}
|
|
465
|
+
else
|
|
466
|
+
{
|
|
467
|
+
SVFUtil::outs() << " Value: ⊥\n";
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
SVFUtil::outs() << "-----------------------------------------\n";
|
|
471
|
+
}
|