svf-tools 1.0.987 → 1.0.989
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/Svfexe/AEDetector.h +15 -2
- package/svf/include/AE/Svfexe/AbsExtAPI.h +147 -0
- package/svf/include/AE/Svfexe/AbstractInterpretation.h +25 -92
- package/svf/include/SVFIR/SVFValue.h +0 -11
- package/svf/include/Util/ExtAPI.h +10 -0
- package/svf/include/Util/SVFUtil.h +1 -7
- package/svf/lib/AE/Svfexe/AEDetector.cpp +108 -28
- package/svf/lib/AE/Svfexe/AbsExtAPI.cpp +765 -0
- package/svf/lib/AE/Svfexe/AbstractInterpretation.cpp +24 -797
- package/svf/lib/SVFIR/SVFFileSystem.cpp +0 -2
- package/svf/lib/Util/ExtAPI.cpp +33 -10
- package/svf/lib/Util/SVFUtil.cpp +0 -15
- package/svf-llvm/include/SVF-LLVM/LLVMModule.h +1 -58
- package/svf-llvm/include/SVF-LLVM/LLVMUtil.h +10 -19
- package/svf-llvm/lib/CHGBuilder.cpp +2 -2
- package/svf-llvm/lib/LLVMModule.cpp +216 -230
- package/svf-llvm/lib/LLVMUtil.cpp +32 -228
- package/svf-llvm/lib/ObjTypeInference.cpp +2 -2
- package/svf-llvm/lib/SVFIRBuilder.cpp +0 -1
- package/svf-llvm/lib/SymbolTableBuilder.cpp +5 -6
- package/svf-llvm/lib/extapi.c +0 -1
|
@@ -0,0 +1,765 @@
|
|
|
1
|
+
//===- AbsExtAPI.cpp -- Abstract Interpretation External API handler-----//
|
|
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
|
+
//
|
|
25
|
+
// Created by Jiawei Wang on 2024/9/9.
|
|
26
|
+
//
|
|
27
|
+
#include "AE/Svfexe/AbsExtAPI.h"
|
|
28
|
+
#include "AE/Svfexe/AbstractInterpretation.h"
|
|
29
|
+
|
|
30
|
+
using namespace SVF;
|
|
31
|
+
AbsExtAPI::AbsExtAPI(Map<const ICFGNode*, AbstractState>& traces): abstractTrace(traces)
|
|
32
|
+
{
|
|
33
|
+
svfir = PAG::getPAG();
|
|
34
|
+
icfg = svfir->getICFG();
|
|
35
|
+
initExtFunMap();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
void AbsExtAPI::initExtFunMap()
|
|
39
|
+
{
|
|
40
|
+
#define SSE_FUNC_PROCESS(LLVM_NAME ,FUNC_NAME) \
|
|
41
|
+
auto sse_##FUNC_NAME = [this](const CallICFGNode *callNode) { \
|
|
42
|
+
/* run real ext function */ \
|
|
43
|
+
AbstractState& as = getAbsStateFromTrace(callNode); \
|
|
44
|
+
u32_t rhs_id = svfir->getValueNode(callNode->getArgument(0)); \
|
|
45
|
+
if (!as.inVarToValTable(rhs_id)) return; \
|
|
46
|
+
u32_t rhs = as[rhs_id].getInterval().lb().getIntNumeral(); \
|
|
47
|
+
s32_t res = FUNC_NAME(rhs); \
|
|
48
|
+
u32_t lhsId = svfir->getValueNode(callNode->getCallSite()); \
|
|
49
|
+
as[lhsId] = IntervalValue(res); \
|
|
50
|
+
return; \
|
|
51
|
+
}; \
|
|
52
|
+
func_map[#FUNC_NAME] = sse_##FUNC_NAME;
|
|
53
|
+
|
|
54
|
+
SSE_FUNC_PROCESS(isalnum, isalnum);
|
|
55
|
+
SSE_FUNC_PROCESS(isalpha, isalpha);
|
|
56
|
+
SSE_FUNC_PROCESS(isblank, isblank);
|
|
57
|
+
SSE_FUNC_PROCESS(iscntrl, iscntrl);
|
|
58
|
+
SSE_FUNC_PROCESS(isdigit, isdigit);
|
|
59
|
+
SSE_FUNC_PROCESS(isgraph, isgraph);
|
|
60
|
+
SSE_FUNC_PROCESS(isprint, isprint);
|
|
61
|
+
SSE_FUNC_PROCESS(ispunct, ispunct);
|
|
62
|
+
SSE_FUNC_PROCESS(isspace, isspace);
|
|
63
|
+
SSE_FUNC_PROCESS(isupper, isupper);
|
|
64
|
+
SSE_FUNC_PROCESS(isxdigit, isxdigit);
|
|
65
|
+
SSE_FUNC_PROCESS(llvm.sin.f64, sin);
|
|
66
|
+
SSE_FUNC_PROCESS(llvm.cos.f64, cos);
|
|
67
|
+
SSE_FUNC_PROCESS(llvm.tan.f64, tan);
|
|
68
|
+
SSE_FUNC_PROCESS(llvm.log.f64, log);
|
|
69
|
+
SSE_FUNC_PROCESS(sinh, sinh);
|
|
70
|
+
SSE_FUNC_PROCESS(cosh, cosh);
|
|
71
|
+
SSE_FUNC_PROCESS(tanh, tanh);
|
|
72
|
+
|
|
73
|
+
auto sse_svf_assert = [this](const CallICFGNode* callNode)
|
|
74
|
+
{
|
|
75
|
+
AbstractInterpretation::getAEInstance().checkpoints.erase(callNode);
|
|
76
|
+
u32_t arg0 = svfir->getValueNode(callNode->getArgument(0));
|
|
77
|
+
AbstractState&as = getAbsStateFromTrace(callNode);
|
|
78
|
+
if (as[arg0].getInterval().equals(IntervalValue(1, 1)))
|
|
79
|
+
{
|
|
80
|
+
SVFUtil::errs() << SVFUtil::sucMsg("The assertion is successfully verified!!\n");
|
|
81
|
+
}
|
|
82
|
+
else
|
|
83
|
+
{
|
|
84
|
+
SVFUtil::errs() <<"svf_assert Fail. " << callNode->toString() << "\n";
|
|
85
|
+
assert(false);
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
};
|
|
89
|
+
func_map["svf_assert"] = sse_svf_assert;
|
|
90
|
+
|
|
91
|
+
auto svf_assert_eq = [this](const CallICFGNode* callNode)
|
|
92
|
+
{
|
|
93
|
+
u32_t arg0 = svfir->getValueNode(callNode->getArgument(0));
|
|
94
|
+
u32_t arg1 = svfir->getValueNode(callNode->getArgument(1));
|
|
95
|
+
AbstractState&as = getAbsStateFromTrace(callNode);
|
|
96
|
+
if (as[arg0].getInterval().equals(as[arg1].getInterval()))
|
|
97
|
+
{
|
|
98
|
+
SVFUtil::errs() << SVFUtil::sucMsg("The assertion is successfully verified!!\n");
|
|
99
|
+
}
|
|
100
|
+
else
|
|
101
|
+
{
|
|
102
|
+
SVFUtil::errs() <<"svf_assert_eq Fail. " << callNode->toString() << "\n";
|
|
103
|
+
assert(false);
|
|
104
|
+
}
|
|
105
|
+
return;
|
|
106
|
+
};
|
|
107
|
+
func_map["svf_assert_eq"] = svf_assert_eq;
|
|
108
|
+
|
|
109
|
+
auto svf_print = [&](const CallICFGNode* callNode)
|
|
110
|
+
{
|
|
111
|
+
if (callNode->arg_size() < 2) return;
|
|
112
|
+
AbstractState&as = getAbsStateFromTrace(callNode);
|
|
113
|
+
u32_t num_id = svfir->getValueNode(callNode->getArgument(0));
|
|
114
|
+
std::string text = strRead(as, getSVFVar(callNode->getArgument(1)));
|
|
115
|
+
assert(as.inVarToValTable(num_id) && "print() should pass integer");
|
|
116
|
+
IntervalValue itv = as[num_id].getInterval();
|
|
117
|
+
std::cout << "Text: " << text <<", Value: " << callNode->getArgument(0)->toString()
|
|
118
|
+
<< ", PrintVal: " << itv.toString() << ", Loc:" << callNode->getSourceLoc() << std::endl;
|
|
119
|
+
return;
|
|
120
|
+
};
|
|
121
|
+
func_map["svf_print"] = svf_print;
|
|
122
|
+
|
|
123
|
+
auto svf_set_value = [&](const CallICFGNode* callNode)
|
|
124
|
+
{
|
|
125
|
+
if (callNode->arg_size() < 2) return;
|
|
126
|
+
AbstractState&as = getAbsStateFromTrace(callNode);
|
|
127
|
+
AbstractValue& num = as[svfir->getValueNode(callNode->getArgument(0))];
|
|
128
|
+
AbstractValue& lb = as[svfir->getValueNode(callNode->getArgument(1))];
|
|
129
|
+
AbstractValue& ub = as[svfir->getValueNode(callNode->getArgument(2))];
|
|
130
|
+
assert(lb.getInterval().is_numeral() && ub.getInterval().is_numeral());
|
|
131
|
+
num.getInterval().set_to_top();
|
|
132
|
+
num.getInterval().meet_with(IntervalValue(lb.getInterval().lb(), ub.getInterval().ub()));
|
|
133
|
+
if (icfg->hasICFGNode(SVFUtil::cast<SVFInstruction>(callNode->getArgument(0))))
|
|
134
|
+
{
|
|
135
|
+
const ICFGNode* node = icfg->getICFGNode(SVFUtil::cast<SVFInstruction>(callNode->getArgument(0)));
|
|
136
|
+
for (const SVFStmt* stmt: node->getSVFStmts())
|
|
137
|
+
{
|
|
138
|
+
if (SVFUtil::isa<LoadStmt>(stmt))
|
|
139
|
+
{
|
|
140
|
+
const LoadStmt* load = SVFUtil::cast<LoadStmt>(stmt);
|
|
141
|
+
NodeID rhsId = load->getRHSVarID();
|
|
142
|
+
as.storeValue(rhsId, num);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return;
|
|
147
|
+
};
|
|
148
|
+
func_map["set_value"] = svf_set_value;
|
|
149
|
+
|
|
150
|
+
auto sse_scanf = [&](const CallICFGNode* callNode)
|
|
151
|
+
{
|
|
152
|
+
AbstractState& as = getAbsStateFromTrace(callNode);
|
|
153
|
+
//scanf("%d", &data);
|
|
154
|
+
if (callNode->arg_size() < 2) return;
|
|
155
|
+
|
|
156
|
+
u32_t dst_id = svfir->getValueNode(callNode->getArgument(1));
|
|
157
|
+
if (!as.inVarToAddrsTable(dst_id))
|
|
158
|
+
{
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
else
|
|
162
|
+
{
|
|
163
|
+
AbstractValue Addrs = as[dst_id];
|
|
164
|
+
for (auto vaddr: Addrs.getAddrs())
|
|
165
|
+
{
|
|
166
|
+
u32_t objId = AbstractState::getInternalID(vaddr);
|
|
167
|
+
AbstractValue range = getRangeLimitFromType(svfir->getGNode(objId)->getType());
|
|
168
|
+
as.store(vaddr, range);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
auto sse_fscanf = [&](const CallICFGNode* callNode)
|
|
173
|
+
{
|
|
174
|
+
//fscanf(stdin, "%d", &data);
|
|
175
|
+
if (callNode->arg_size() < 3) return;
|
|
176
|
+
AbstractState& as = getAbsStateFromTrace(callNode);
|
|
177
|
+
u32_t dst_id = svfir->getValueNode(callNode->getArgument(2));
|
|
178
|
+
if (!as.inVarToAddrsTable(dst_id))
|
|
179
|
+
{
|
|
180
|
+
}
|
|
181
|
+
else
|
|
182
|
+
{
|
|
183
|
+
AbstractValue Addrs = as[dst_id];
|
|
184
|
+
for (auto vaddr: Addrs.getAddrs())
|
|
185
|
+
{
|
|
186
|
+
u32_t objId = AbstractState::getInternalID(vaddr);
|
|
187
|
+
AbstractValue range = getRangeLimitFromType(svfir->getGNode(objId)->getType());
|
|
188
|
+
as.store(vaddr, range);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
func_map["__isoc99_fscanf"] = sse_fscanf;
|
|
194
|
+
func_map["__isoc99_scanf"] = sse_scanf;
|
|
195
|
+
func_map["__isoc99_vscanf"] = sse_scanf;
|
|
196
|
+
func_map["fscanf"] = sse_fscanf;
|
|
197
|
+
func_map["scanf"] = sse_scanf;
|
|
198
|
+
func_map["sscanf"] = sse_scanf;
|
|
199
|
+
func_map["__isoc99_sscanf"] = sse_scanf;
|
|
200
|
+
func_map["vscanf"] = sse_scanf;
|
|
201
|
+
|
|
202
|
+
auto sse_fread = [&](const CallICFGNode *callNode)
|
|
203
|
+
{
|
|
204
|
+
if (callNode->arg_size() < 3) return;
|
|
205
|
+
AbstractState&as = getAbsStateFromTrace(callNode);
|
|
206
|
+
u32_t block_count_id = svfir->getValueNode(callNode->getArgument(2));
|
|
207
|
+
u32_t block_size_id = svfir->getValueNode(callNode->getArgument(1));
|
|
208
|
+
IntervalValue block_count = as[block_count_id].getInterval();
|
|
209
|
+
IntervalValue block_size = as[block_size_id].getInterval();
|
|
210
|
+
IntervalValue block_byte = block_count * block_size;
|
|
211
|
+
};
|
|
212
|
+
func_map["fread"] = sse_fread;
|
|
213
|
+
|
|
214
|
+
auto sse_sprintf = [&](const CallICFGNode *callNode)
|
|
215
|
+
{
|
|
216
|
+
// printf is difficult to predict since it has no byte size arguments
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
auto sse_snprintf = [&](const CallICFGNode *callNode)
|
|
220
|
+
{
|
|
221
|
+
if (callNode->arg_size() < 2) return;
|
|
222
|
+
AbstractState&as = getAbsStateFromTrace(callNode);
|
|
223
|
+
u32_t size_id = svfir->getValueNode(callNode->getArgument(1));
|
|
224
|
+
u32_t dst_id = svfir->getValueNode(callNode->getArgument(0));
|
|
225
|
+
// get elem size of arg2
|
|
226
|
+
u32_t elemSize = 1;
|
|
227
|
+
if (callNode->getArgument(2)->getType()->isArrayTy())
|
|
228
|
+
{
|
|
229
|
+
elemSize = SVFUtil::dyn_cast<SVFArrayType>(callNode->getArgument(2)->getType())->getTypeOfElement()->getByteSize();
|
|
230
|
+
}
|
|
231
|
+
else if (callNode->getArgument(2)->getType()->isPointerTy())
|
|
232
|
+
{
|
|
233
|
+
elemSize = as.getPointeeElement(svfir->getValueNode(callNode->getArgument(2)))->getByteSize();
|
|
234
|
+
}
|
|
235
|
+
else
|
|
236
|
+
{
|
|
237
|
+
return;
|
|
238
|
+
// assert(false && "we cannot support this type");
|
|
239
|
+
}
|
|
240
|
+
IntervalValue size = as[size_id].getInterval() * IntervalValue(elemSize) - IntervalValue(1);
|
|
241
|
+
if (!as.inVarToAddrsTable(dst_id))
|
|
242
|
+
{
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
func_map["__snprintf_chk"] = sse_snprintf;
|
|
246
|
+
func_map["__vsprintf_chk"] = sse_sprintf;
|
|
247
|
+
func_map["__sprintf_chk"] = sse_sprintf;
|
|
248
|
+
func_map["snprintf"] = sse_snprintf;
|
|
249
|
+
func_map["sprintf"] = sse_sprintf;
|
|
250
|
+
func_map["vsprintf"] = sse_sprintf;
|
|
251
|
+
func_map["vsnprintf"] = sse_snprintf;
|
|
252
|
+
func_map["__vsnprintf_chk"] = sse_snprintf;
|
|
253
|
+
func_map["swprintf"] = sse_snprintf;
|
|
254
|
+
func_map["_snwprintf"] = sse_snprintf;
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
auto sse_itoa = [&](const CallICFGNode* callNode)
|
|
258
|
+
{
|
|
259
|
+
// itoa(num, ch, 10);
|
|
260
|
+
// num: int, ch: char*, 10 is decimal
|
|
261
|
+
if (callNode->arg_size() < 3) return;
|
|
262
|
+
AbstractState&as = getAbsStateFromTrace(callNode);
|
|
263
|
+
u32_t num_id = svfir->getValueNode(callNode->getArgument(0));
|
|
264
|
+
|
|
265
|
+
u32_t num = (u32_t) as[num_id].getInterval().getNumeral();
|
|
266
|
+
std::string snum = std::to_string(num);
|
|
267
|
+
};
|
|
268
|
+
func_map["itoa"] = sse_itoa;
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
auto sse_strlen = [&](const CallICFGNode *callNode)
|
|
272
|
+
{
|
|
273
|
+
// check the arg size
|
|
274
|
+
if (callNode->arg_size() < 1) return;
|
|
275
|
+
const SVFValue* strValue = callNode->getArgument(0);
|
|
276
|
+
AbstractState& as = getAbsStateFromTrace(callNode);
|
|
277
|
+
NodeID value_id = svfir->getValueNode(strValue);
|
|
278
|
+
u32_t lhsId = svfir->getValueNode(callNode->getCallSite());
|
|
279
|
+
u32_t dst_size = 0;
|
|
280
|
+
for (const auto& addr : as[value_id].getAddrs())
|
|
281
|
+
{
|
|
282
|
+
NodeID objId = AbstractState::getInternalID(addr);
|
|
283
|
+
if (svfir->getBaseObj(objId)->isConstantByteSize())
|
|
284
|
+
{
|
|
285
|
+
dst_size = svfir->getBaseObj(objId)->getByteSizeOfObj();
|
|
286
|
+
}
|
|
287
|
+
else
|
|
288
|
+
{
|
|
289
|
+
const ICFGNode* addrNode = svfir->getICFG()->getICFGNode(SVFUtil::cast<SVFInstruction>(svfir->getBaseObj(objId)->getValue()));
|
|
290
|
+
for (const SVFStmt* stmt2: addrNode->getSVFStmts())
|
|
291
|
+
{
|
|
292
|
+
if (const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt2))
|
|
293
|
+
{
|
|
294
|
+
dst_size = as.getAllocaInstByteSize(addrStmt);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
u32_t len = 0;
|
|
300
|
+
NodeID dstid = svfir->getValueNode(strValue);
|
|
301
|
+
if (as.inVarToAddrsTable(dstid))
|
|
302
|
+
{
|
|
303
|
+
for (u32_t index = 0; index < dst_size; index++)
|
|
304
|
+
{
|
|
305
|
+
AbstractValue expr0 =
|
|
306
|
+
as.getGepObjAddrs(dstid, IntervalValue(index));
|
|
307
|
+
AbstractValue val;
|
|
308
|
+
for (const auto &addr: expr0.getAddrs())
|
|
309
|
+
{
|
|
310
|
+
val.join_with(as.load(addr));
|
|
311
|
+
}
|
|
312
|
+
if (val.getInterval().is_numeral() && (char) val.getInterval().getIntNumeral() == '\0')
|
|
313
|
+
{
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
++len;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (len == 0)
|
|
320
|
+
{
|
|
321
|
+
as[lhsId] = IntervalValue((s64_t)0, (s64_t)Options::MaxFieldLimit());
|
|
322
|
+
}
|
|
323
|
+
else
|
|
324
|
+
{
|
|
325
|
+
as[lhsId] = IntervalValue(len);
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
func_map["strlen"] = sse_strlen;
|
|
329
|
+
func_map["wcslen"] = sse_strlen;
|
|
330
|
+
|
|
331
|
+
auto sse_recv = [&](const CallICFGNode *callNode)
|
|
332
|
+
{
|
|
333
|
+
// recv(sockfd, buf, len, flags);
|
|
334
|
+
if (callNode->arg_size() < 4) return;
|
|
335
|
+
AbstractState&as = getAbsStateFromTrace(callNode);
|
|
336
|
+
u32_t len_id = svfir->getValueNode(callNode->getArgument(2));
|
|
337
|
+
IntervalValue len = as[len_id].getInterval() - IntervalValue(1);
|
|
338
|
+
u32_t lhsId = svfir->getValueNode(callNode->getCallSite());
|
|
339
|
+
as[lhsId] = len;
|
|
340
|
+
};
|
|
341
|
+
func_map["recv"] = sse_recv;
|
|
342
|
+
func_map["__recv"] = sse_recv;
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
AbstractState& AbsExtAPI::getAbsStateFromTrace(const SVF::ICFGNode* node)
|
|
346
|
+
{
|
|
347
|
+
const ICFGNode* repNode = icfg->getRepNode(node);
|
|
348
|
+
if (abstractTrace.count(repNode) == 0)
|
|
349
|
+
{
|
|
350
|
+
assert(0 && "No preAbsTrace for this node");
|
|
351
|
+
}
|
|
352
|
+
else
|
|
353
|
+
{
|
|
354
|
+
return abstractTrace[repNode];
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
std::string AbsExtAPI::strRead(AbstractState& as, const SVFVar* rhs)
|
|
359
|
+
{
|
|
360
|
+
// sse read string nodeID->string
|
|
361
|
+
std::string str0;
|
|
362
|
+
|
|
363
|
+
for (u32_t index = 0; index < Options::MaxFieldLimit(); index++)
|
|
364
|
+
{
|
|
365
|
+
// dead loop for string and break if there's a \0. If no \0, it will throw err.
|
|
366
|
+
if (!as.inVarToAddrsTable(rhs->getId())) continue;
|
|
367
|
+
AbstractValue expr0 =
|
|
368
|
+
as.getGepObjAddrs(rhs->getId(), IntervalValue(index));
|
|
369
|
+
|
|
370
|
+
AbstractValue val;
|
|
371
|
+
for (const auto &addr: expr0.getAddrs())
|
|
372
|
+
{
|
|
373
|
+
val.join_with(as.load(addr));
|
|
374
|
+
}
|
|
375
|
+
if (!val.getInterval().is_numeral())
|
|
376
|
+
{
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
if ((char) val.getInterval().getIntNumeral() == '\0')
|
|
380
|
+
{
|
|
381
|
+
break;
|
|
382
|
+
}
|
|
383
|
+
str0.push_back((char) val.getInterval().getIntNumeral());
|
|
384
|
+
}
|
|
385
|
+
return str0;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
void AbsExtAPI::handleExtAPI(const CallICFGNode *call)
|
|
389
|
+
{
|
|
390
|
+
AbstractState& as = getAbsStateFromTrace(call);
|
|
391
|
+
const SVFFunction *fun = call->getCalledFunction();
|
|
392
|
+
assert(fun && "SVFFunction* is nullptr");
|
|
393
|
+
ExtAPIType extType = UNCLASSIFIED;
|
|
394
|
+
// get type of mem api
|
|
395
|
+
for (const std::string &annotation: ExtAPI::getExtAPI()->getExtFuncAnnotations(fun))
|
|
396
|
+
{
|
|
397
|
+
if (annotation.find("MEMCPY") != std::string::npos)
|
|
398
|
+
extType = MEMCPY;
|
|
399
|
+
if (annotation.find("MEMSET") != std::string::npos)
|
|
400
|
+
extType = MEMSET;
|
|
401
|
+
if (annotation.find("STRCPY") != std::string::npos)
|
|
402
|
+
extType = STRCPY;
|
|
403
|
+
if (annotation.find("STRCAT") != std::string::npos)
|
|
404
|
+
extType = STRCAT;
|
|
405
|
+
}
|
|
406
|
+
if (extType == UNCLASSIFIED)
|
|
407
|
+
{
|
|
408
|
+
if (func_map.find(fun->getName()) != func_map.end())
|
|
409
|
+
{
|
|
410
|
+
func_map[fun->getName()](call);
|
|
411
|
+
}
|
|
412
|
+
else
|
|
413
|
+
{
|
|
414
|
+
u32_t lhsId = svfir->getValueNode(call->getCallSite());
|
|
415
|
+
if (as.inVarToAddrsTable(lhsId))
|
|
416
|
+
{
|
|
417
|
+
|
|
418
|
+
}
|
|
419
|
+
else
|
|
420
|
+
{
|
|
421
|
+
as[lhsId] = IntervalValue();
|
|
422
|
+
}
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
// 1. memcpy functions like memcpy_chk, strncpy, annotate("MEMCPY"), annotate("BUF_CHECK:Arg0, Arg2"), annotate("BUF_CHECK:Arg1, Arg2")
|
|
427
|
+
else if (extType == MEMCPY)
|
|
428
|
+
{
|
|
429
|
+
IntervalValue len = as[svfir->getValueNode(call->getArgument(2))].getInterval();
|
|
430
|
+
svfir->getGNode(svfir->getValueNode(call->getArgument(0)));
|
|
431
|
+
handleMemcpy(as, getSVFVar(call->getArgument(0)), getSVFVar(call->getArgument(1)), len, 0);
|
|
432
|
+
}
|
|
433
|
+
else if (extType == MEMSET)
|
|
434
|
+
{
|
|
435
|
+
// memset dst is arg0, elem is arg1, size is arg2
|
|
436
|
+
IntervalValue len = as[svfir->getValueNode(call->getArgument(2))].getInterval();
|
|
437
|
+
IntervalValue elem = as[svfir->getValueNode(call->getArgument(1))].getInterval();
|
|
438
|
+
handleMemset(as, getSVFVar(call->getArgument(0)), elem, len);
|
|
439
|
+
}
|
|
440
|
+
else if (extType == STRCPY)
|
|
441
|
+
{
|
|
442
|
+
handleStrcpy(call);
|
|
443
|
+
}
|
|
444
|
+
else if (extType == STRCAT)
|
|
445
|
+
{
|
|
446
|
+
handleStrcat(call);
|
|
447
|
+
}
|
|
448
|
+
else
|
|
449
|
+
{
|
|
450
|
+
|
|
451
|
+
}
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
void AbsExtAPI::handleStrcpy(const CallICFGNode *call)
|
|
456
|
+
{
|
|
457
|
+
// strcpy, __strcpy_chk, stpcpy , wcscpy, __wcscpy_chk
|
|
458
|
+
// get the dst and src
|
|
459
|
+
AbstractState& as = getAbsStateFromTrace(call);
|
|
460
|
+
const SVFVar* arg0Val = getSVFVar(call->getArgument(0));
|
|
461
|
+
const SVFVar* arg1Val = getSVFVar(call->getArgument(1));
|
|
462
|
+
IntervalValue strLen = getStrlen(as, arg1Val);
|
|
463
|
+
// no need to -1, since it has \0 as the last byte
|
|
464
|
+
handleMemcpy(as, arg0Val, arg1Val, strLen, strLen.lb().getIntNumeral());
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
IntervalValue AbsExtAPI::getStrlen(AbstractState& as, const SVF::SVFVar *strValue)
|
|
468
|
+
{
|
|
469
|
+
NodeID value_id = strValue->getId();
|
|
470
|
+
u32_t dst_size = 0;
|
|
471
|
+
for (const auto& addr : as[value_id].getAddrs())
|
|
472
|
+
{
|
|
473
|
+
NodeID objId = AbstractState::getInternalID(addr);
|
|
474
|
+
if (svfir->getBaseObj(objId)->isConstantByteSize())
|
|
475
|
+
{
|
|
476
|
+
dst_size = svfir->getBaseObj(objId)->getByteSizeOfObj();
|
|
477
|
+
}
|
|
478
|
+
else
|
|
479
|
+
{
|
|
480
|
+
const ICFGNode* addrNode = svfir->getICFG()->getICFGNode(SVFUtil::cast<SVFInstruction>(svfir->getBaseObj(objId)->getValue()));
|
|
481
|
+
for (const SVFStmt* stmt2: addrNode->getSVFStmts())
|
|
482
|
+
{
|
|
483
|
+
if (const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt2))
|
|
484
|
+
{
|
|
485
|
+
dst_size = as.getAllocaInstByteSize(addrStmt);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
u32_t len = 0;
|
|
491
|
+
u32_t elemSize = 1;
|
|
492
|
+
if (as.inVarToAddrsTable(value_id))
|
|
493
|
+
{
|
|
494
|
+
for (u32_t index = 0; index < dst_size; index++)
|
|
495
|
+
{
|
|
496
|
+
AbstractValue expr0 =
|
|
497
|
+
as.getGepObjAddrs(value_id, IntervalValue(index));
|
|
498
|
+
AbstractValue val;
|
|
499
|
+
for (const auto &addr: expr0.getAddrs())
|
|
500
|
+
{
|
|
501
|
+
val.join_with(as.load(addr));
|
|
502
|
+
}
|
|
503
|
+
if (val.getInterval().is_numeral() && (char) val.getInterval().getIntNumeral() == '\0')
|
|
504
|
+
{
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
++len;
|
|
508
|
+
}
|
|
509
|
+
if (strValue->getType()->isArrayTy())
|
|
510
|
+
{
|
|
511
|
+
elemSize = SVFUtil::dyn_cast<SVFArrayType>(strValue->getType())->getTypeOfElement()->getByteSize();
|
|
512
|
+
}
|
|
513
|
+
else if (strValue->getType()->isPointerTy())
|
|
514
|
+
{
|
|
515
|
+
if (const SVFType* elemType = as.getPointeeElement(value_id))
|
|
516
|
+
{
|
|
517
|
+
if (elemType->isArrayTy())
|
|
518
|
+
elemSize = SVFUtil::dyn_cast<SVFArrayType>(elemType)->getTypeOfElement()->getByteSize();
|
|
519
|
+
else
|
|
520
|
+
elemSize = elemType->getByteSize();
|
|
521
|
+
}
|
|
522
|
+
else
|
|
523
|
+
{
|
|
524
|
+
elemSize = 1;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
else
|
|
528
|
+
{
|
|
529
|
+
assert(false && "we cannot support this type");
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
if (len == 0)
|
|
533
|
+
{
|
|
534
|
+
return IntervalValue((s64_t)0, (s64_t)Options::MaxFieldLimit());
|
|
535
|
+
}
|
|
536
|
+
else
|
|
537
|
+
{
|
|
538
|
+
return IntervalValue(len * elemSize);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
void AbsExtAPI::handleStrcat(const SVF::CallICFGNode *call)
|
|
544
|
+
{
|
|
545
|
+
// __strcat_chk, strcat, __wcscat_chk, wcscat, __strncat_chk, strncat, __wcsncat_chk, wcsncat
|
|
546
|
+
// to check it is strcat group or strncat group
|
|
547
|
+
AbstractState& as = getAbsStateFromTrace(call);
|
|
548
|
+
const SVFFunction *fun = call->getCalledFunction();
|
|
549
|
+
const std::vector<std::string> strcatGroup = {"__strcat_chk", "strcat", "__wcscat_chk", "wcscat"};
|
|
550
|
+
const std::vector<std::string> strncatGroup = {"__strncat_chk", "strncat", "__wcsncat_chk", "wcsncat"};
|
|
551
|
+
if (std::find(strcatGroup.begin(), strcatGroup.end(), fun->getName()) != strcatGroup.end())
|
|
552
|
+
{
|
|
553
|
+
const SVFVar* arg0Val = getSVFVar(call->getArgument(0));
|
|
554
|
+
const SVFVar* arg1Val = getSVFVar(call->getArgument(1));
|
|
555
|
+
IntervalValue strLen0 = getStrlen(as, arg0Val);
|
|
556
|
+
IntervalValue strLen1 = getStrlen(as, arg1Val);
|
|
557
|
+
IntervalValue totalLen = strLen0 + strLen1;
|
|
558
|
+
handleMemcpy(as, arg0Val, arg1Val, strLen1, strLen0.lb().getIntNumeral());
|
|
559
|
+
// do memcpy
|
|
560
|
+
}
|
|
561
|
+
else if (std::find(strncatGroup.begin(), strncatGroup.end(), fun->getName()) != strncatGroup.end())
|
|
562
|
+
{
|
|
563
|
+
const SVFVar* arg0Val = getSVFVar(call->getArgument(0));
|
|
564
|
+
const SVFVar* arg1Val = getSVFVar(call->getArgument(1));
|
|
565
|
+
const SVFVar* arg2Val = getSVFVar(call->getArgument(2));
|
|
566
|
+
IntervalValue arg2Num = as[arg2Val->getId()].getInterval();
|
|
567
|
+
IntervalValue strLen0 = getStrlen(as, arg0Val);
|
|
568
|
+
IntervalValue totalLen = strLen0 + arg2Num;
|
|
569
|
+
handleMemcpy(as, arg0Val, arg1Val, arg2Num, strLen0.lb().getIntNumeral());
|
|
570
|
+
// do memcpy
|
|
571
|
+
}
|
|
572
|
+
else
|
|
573
|
+
{
|
|
574
|
+
assert(false && "unknown strcat function, please add it to strcatGroup or strncatGroup");
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
void AbsExtAPI::handleMemcpy(AbstractState& as, const SVF::SVFVar *dst, const SVF::SVFVar *src, IntervalValue len, u32_t start_idx)
|
|
579
|
+
{
|
|
580
|
+
u32_t dstId = dst->getId(); // pts(dstId) = {objid} objbar objtypeinfo->getType().
|
|
581
|
+
u32_t srcId = src->getId();
|
|
582
|
+
u32_t elemSize = 1;
|
|
583
|
+
if (dst->getType()->isArrayTy())
|
|
584
|
+
{
|
|
585
|
+
elemSize = SVFUtil::dyn_cast<SVFArrayType>(dst->getType())->getTypeOfElement()->getByteSize();
|
|
586
|
+
}
|
|
587
|
+
// memcpy(i32*, i32*, 40)
|
|
588
|
+
else if (dst->getType()->isPointerTy())
|
|
589
|
+
{
|
|
590
|
+
if (const SVFType* elemType = as.getPointeeElement(dstId))
|
|
591
|
+
{
|
|
592
|
+
if (elemType->isArrayTy())
|
|
593
|
+
elemSize = SVFUtil::dyn_cast<SVFArrayType>(elemType)->getTypeOfElement()->getByteSize();
|
|
594
|
+
else
|
|
595
|
+
elemSize = elemType->getByteSize();
|
|
596
|
+
}
|
|
597
|
+
else
|
|
598
|
+
{
|
|
599
|
+
elemSize = 1;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
else
|
|
603
|
+
{
|
|
604
|
+
assert(false && "we cannot support this type");
|
|
605
|
+
}
|
|
606
|
+
u32_t size = std::min((u32_t)Options::MaxFieldLimit(), (u32_t) len.lb().getIntNumeral());
|
|
607
|
+
u32_t range_val = size / elemSize;
|
|
608
|
+
if (as.inVarToAddrsTable(srcId) && as.inVarToAddrsTable(dstId))
|
|
609
|
+
{
|
|
610
|
+
for (u32_t index = 0; index < range_val; index++)
|
|
611
|
+
{
|
|
612
|
+
// dead loop for string and break if there's a \0. If no \0, it will throw err.
|
|
613
|
+
AbstractValue expr_src =
|
|
614
|
+
as.getGepObjAddrs(srcId, IntervalValue(index));
|
|
615
|
+
AbstractValue expr_dst =
|
|
616
|
+
as.getGepObjAddrs(dstId, IntervalValue(index + start_idx));
|
|
617
|
+
for (const auto &dst: expr_dst.getAddrs())
|
|
618
|
+
{
|
|
619
|
+
for (const auto &src: expr_src.getAddrs())
|
|
620
|
+
{
|
|
621
|
+
u32_t objId = AbstractState::getInternalID(src);
|
|
622
|
+
if (as.inAddrToValTable(objId))
|
|
623
|
+
{
|
|
624
|
+
as.store(dst, as.load(src));
|
|
625
|
+
}
|
|
626
|
+
else if (as.inAddrToAddrsTable(objId))
|
|
627
|
+
{
|
|
628
|
+
as.store(dst, as.load(src));
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
void AbsExtAPI::handleMemset(AbstractState& as, const SVF::SVFVar *dst, IntervalValue elem, IntervalValue len)
|
|
637
|
+
{
|
|
638
|
+
u32_t dstId = dst->getId();
|
|
639
|
+
u32_t size = std::min((u32_t)Options::MaxFieldLimit(), (u32_t) len.lb().getIntNumeral());
|
|
640
|
+
u32_t elemSize = 1;
|
|
641
|
+
if (dst->getType()->isArrayTy())
|
|
642
|
+
{
|
|
643
|
+
elemSize = SVFUtil::dyn_cast<SVFArrayType>(dst->getType())->getTypeOfElement()->getByteSize();
|
|
644
|
+
}
|
|
645
|
+
else if (dst->getType()->isPointerTy())
|
|
646
|
+
{
|
|
647
|
+
if (const SVFType* elemType = as.getPointeeElement(dstId))
|
|
648
|
+
{
|
|
649
|
+
elemSize = elemType->getByteSize();
|
|
650
|
+
}
|
|
651
|
+
else
|
|
652
|
+
{
|
|
653
|
+
elemSize = 1;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
else
|
|
657
|
+
{
|
|
658
|
+
assert(false && "we cannot support this type");
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
u32_t range_val = size / elemSize;
|
|
662
|
+
for (u32_t index = 0; index < range_val; index++)
|
|
663
|
+
{
|
|
664
|
+
// dead loop for string and break if there's a \0. If no \0, it will throw err.
|
|
665
|
+
if (as.inVarToAddrsTable(dstId))
|
|
666
|
+
{
|
|
667
|
+
AbstractValue lhs_gep = as.getGepObjAddrs(dstId, IntervalValue(index));
|
|
668
|
+
for (const auto &addr: lhs_gep.getAddrs())
|
|
669
|
+
{
|
|
670
|
+
u32_t objId = AbstractState::getInternalID(addr);
|
|
671
|
+
if (as.inAddrToValTable(objId))
|
|
672
|
+
{
|
|
673
|
+
AbstractValue tmp = as.load(addr);
|
|
674
|
+
tmp.join_with(elem);
|
|
675
|
+
as.store(addr, tmp);
|
|
676
|
+
}
|
|
677
|
+
else
|
|
678
|
+
{
|
|
679
|
+
as.store(addr, elem);
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
else
|
|
684
|
+
break;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* This function, getRangeLimitFromType, calculates the lower and upper bounds of
|
|
690
|
+
* a numeric range for a given SVFType. It is used to determine the possible value
|
|
691
|
+
* range of integer types. If the type is an SVFIntegerType, it calculates the bounds
|
|
692
|
+
* based on the size and signedness of the type. The calculated bounds are returned
|
|
693
|
+
* as an IntervalValue representing the lower (lb) and upper (ub) limits of the range.
|
|
694
|
+
*
|
|
695
|
+
* @param type The SVFType for which to calculate the value range.
|
|
696
|
+
*
|
|
697
|
+
* @return An IntervalValue representing the lower and upper bounds of the range.
|
|
698
|
+
*/
|
|
699
|
+
IntervalValue AbsExtAPI::getRangeLimitFromType(const SVFType* type)
|
|
700
|
+
{
|
|
701
|
+
if (const SVFIntegerType* intType = SVFUtil::dyn_cast<SVFIntegerType>(type))
|
|
702
|
+
{
|
|
703
|
+
u32_t bits = type->getByteSize() * 8;
|
|
704
|
+
s64_t ub = 0;
|
|
705
|
+
s64_t lb = 0;
|
|
706
|
+
if (bits >= 32)
|
|
707
|
+
{
|
|
708
|
+
if (intType->isSigned())
|
|
709
|
+
{
|
|
710
|
+
ub = static_cast<s64_t>(std::numeric_limits<s32_t>::max());
|
|
711
|
+
lb = static_cast<s64_t>(std::numeric_limits<s32_t>::min());
|
|
712
|
+
}
|
|
713
|
+
else
|
|
714
|
+
{
|
|
715
|
+
ub = static_cast<s64_t>(std::numeric_limits<u32_t>::max());
|
|
716
|
+
lb = static_cast<s64_t>(std::numeric_limits<u32_t>::min());
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
else if (bits == 16)
|
|
720
|
+
{
|
|
721
|
+
if (intType->isSigned())
|
|
722
|
+
{
|
|
723
|
+
ub = static_cast<s64_t>(std::numeric_limits<s16_t>::max());
|
|
724
|
+
lb = static_cast<s64_t>(std::numeric_limits<s16_t>::min());
|
|
725
|
+
}
|
|
726
|
+
else
|
|
727
|
+
{
|
|
728
|
+
ub = static_cast<s64_t>(std::numeric_limits<u16_t>::max());
|
|
729
|
+
lb = static_cast<s64_t>(std::numeric_limits<u16_t>::min());
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
else if (bits == 8)
|
|
733
|
+
{
|
|
734
|
+
if (intType->isSigned())
|
|
735
|
+
{
|
|
736
|
+
ub = static_cast<s64_t>(std::numeric_limits<int8_t>::max());
|
|
737
|
+
lb = static_cast<s64_t>(std::numeric_limits<int8_t>::min());
|
|
738
|
+
}
|
|
739
|
+
else
|
|
740
|
+
{
|
|
741
|
+
ub = static_cast<s64_t>(std::numeric_limits<u_int8_t>::max());
|
|
742
|
+
lb = static_cast<s64_t>(std::numeric_limits<u_int8_t>::min());
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
return IntervalValue(lb, ub);
|
|
746
|
+
}
|
|
747
|
+
else if (SVFUtil::isa<SVFOtherType>(type))
|
|
748
|
+
{
|
|
749
|
+
// handle other type like float double, set s32_t as the range
|
|
750
|
+
s64_t ub = static_cast<s64_t>(std::numeric_limits<s32_t>::max());
|
|
751
|
+
s64_t lb = static_cast<s64_t>(std::numeric_limits<s32_t>::min());
|
|
752
|
+
return IntervalValue(lb, ub);
|
|
753
|
+
}
|
|
754
|
+
else
|
|
755
|
+
{
|
|
756
|
+
return IntervalValue::top();
|
|
757
|
+
// other types, return top interval
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
const SVFVar* AbsExtAPI::getSVFVar(const SVF::SVFValue* val)
|
|
762
|
+
{
|
|
763
|
+
assert(svfir->hasGNode(svfir->getValueNode(val)));
|
|
764
|
+
return svfir->getGNode(svfir->getValueNode(val));
|
|
765
|
+
}
|