svf-tools 1.0.1194 → 1.0.1195
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 +3 -3
- package/svf/include/AE/Core/AddressValue.h +2 -2
- package/svf/include/AE/Svfexe/AbsExtAPI.h +12 -32
- package/svf/include/AE/Svfexe/AbstractInterpretation.h +13 -3
- package/svf/lib/AE/Svfexe/AEDetector.cpp +20 -4
- package/svf/lib/AE/Svfexe/AbsExtAPI.cpp +153 -193
- package/svf/lib/AE/Svfexe/AbstractInterpretation.cpp +189 -56
- package/SVF-doxygen/doxygen.config +0 -2548
- package/SVF-doxygen/wiki/PAG.png +0 -0
- package/SVF-doxygen/wiki/andersen.png +0 -0
- package/SVF-doxygen/wiki/callgraph.png +0 -0
- package/SVF-doxygen/wiki/consG.png +0 -0
- package/SVF-doxygen/wiki/cpu2000-flto +0 -432
- package/SVF-doxygen/wiki/cpu2006-flto +0 -417
- package/SVF-doxygen/wiki/cpu2017-wllvm.cfg +0 -999
- package/SVF-doxygen/wiki/database.png +0 -0
- package/SVF-doxygen/wiki/framework.png +0 -0
- package/SVF-doxygen/wiki/help.png +0 -0
- package/SVF-doxygen/wiki/icfg.png +0 -0
- package/SVF-doxygen/wiki/mssa-cha.png +0 -0
- package/SVF-doxygen/wiki/pagedge.png +0 -0
- package/SVF-doxygen/wiki/pagnode.png +0 -0
- package/SVF-doxygen/wiki/pt.png +0 -0
- package/SVF-doxygen/wiki/setupcmake.png +0 -0
- package/SVF-doxygen/wiki/setupconfiguration.png +0 -0
- package/SVF-doxygen/wiki/setupdashboard.png +0 -0
- package/SVF-doxygen/wiki/setupdebug.png +0 -0
- package/SVF-doxygen/wiki/setupenv.png +0 -0
- package/SVF-doxygen/wiki/startup.png +0 -0
- package/SVF-doxygen/wiki/svf-stat.pdf +0 -0
- package/SVF-doxygen/wiki/svfg-framework.png +0 -0
- package/SVF-doxygen/wiki/svfg.png +0 -0
- package/SVF-doxygen/wiki/svfg_opt.png +0 -0
- package/SVF-doxygen/wiki/svfgedge-cha.png +0 -0
- package/SVF-doxygen/wiki/svfgnode-cha.png +0 -0
- package/SVF-doxygen/wiki/svfpic/README.md +0 -6
- package/SVF-doxygen/wiki/svfpic/ass-1debug1.png +0 -0
- package/SVF-doxygen/wiki/svfpic/ass-1debug2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/build.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/cmd.png +0 -0
- package/SVF-doxygen/wiki/svfpic/connect1.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/connect2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/connect3.png +0 -0
- package/SVF-doxygen/wiki/svfpic/connect4.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/connect5.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/connect6.png +0 -0
- package/SVF-doxygen/wiki/svfpic/connect7.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/continue.png +0 -0
- package/SVF-doxygen/wiki/svfpic/debug-new.png +0 -0
- package/SVF-doxygen/wiki/svfpic/debug-new2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/debug1.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/debug2.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/debug3.png +0 -0
- package/SVF-doxygen/wiki/svfpic/debug4.png +0 -0
- package/SVF-doxygen/wiki/svfpic/debug5.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/debug6.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/docker_sys_requirement.png +0 -0
- package/SVF-doxygen/wiki/svfpic/docker_sys_requirements.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerbuild.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerbuild2.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerbuild3.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerbuild4.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerbuild5.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerbuildimage.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockercmd.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockercmd2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockercontainer.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb1.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb10.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb2.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb3.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb4.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb5.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb6.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb7.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb8.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb9.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerfinshbuilt.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerimage.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockernameImage.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerpull.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerpull2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/download.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/extension1.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/extension2.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/graphviz.png +0 -0
- package/SVF-doxygen/wiki/svfpic/hellodb.png +0 -0
- package/SVF-doxygen/wiki/svfpic/hellodb2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/hviz_0.png +0 -0
- package/SVF-doxygen/wiki/svfpic/hviz_1.png +0 -0
- package/SVF-doxygen/wiki/svfpic/hviz_2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/installC:C++Ext.png +0 -0
- package/SVF-doxygen/wiki/svfpic/installCMakeExt.png +0 -0
- package/SVF-doxygen/wiki/svfpic/installRCext.png +0 -0
- package/SVF-doxygen/wiki/svfpic/installdockerext.png +0 -0
- package/SVF-doxygen/wiki/svfpic/launch1.png +0 -0
- package/SVF-doxygen/wiki/svfpic/openfile.png +0 -0
- package/SVF-doxygen/wiki/svfpic/pathfolder.png +0 -0
- package/SVF-doxygen/wiki/svfpic/restart.png +0 -0
- package/SVF-doxygen/wiki/svfpic/rundocker.png +0 -0
- package/SVF-doxygen/wiki/svfpic/runinCLI.png +0 -0
- package/SVF-doxygen/wiki/svfpic/screen.png +0 -0
- package/SVF-doxygen/wiki/svfpic/settings1.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/settings2.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/settings3.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/shortlists.png +0 -0
- package/SVF-doxygen/wiki/svfpic/start.png +0 -0
- package/SVF-doxygen/wiki/svfpic/start1.png +0 -0
- package/SVF-doxygen/wiki/svfpic/update0.png +0 -0
- package/SVF-doxygen/wiki/svfpic/verify_docker.png +0 -0
- package/SVF-doxygen/wiki/svfpic/vs_entry_window.png +0 -0
- package/SVF-doxygen/wiki/svfpic/wsl.png +0 -0
- package/SVF-doxygen/wiki/svfpic/wsl_1.png +0 -0
- package/SVF-doxygen/wiki/svfpic/wsl_2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/wsl_3.png +0 -0
- package/SVF-doxygen/wiki/tools.png +0 -0
- package/SVF-doxygen/wiki/users.png +0 -0
- package/SVF-doxygen/wiki/vm1.png +0 -0
- package/SVF-doxygen/wiki/vm2.png +0 -0
- package/SVF-doxygen/wiki/vm3.png +0 -0
- package/SVF-doxygen/wiki/vm4.png +0 -0
- package/SVF-doxygen/wiki/vm5.png +0 -0
- package/SVF-doxygen/wiki/vscode_build_tasks.png +0 -0
- package/SVF-doxygen/wiki/vscode_cpp_extension.png +0 -0
- package/SVF-doxygen/wiki/vscode_debug_list.png +0 -0
- package/SVF-doxygen/wiki/vscode_dir_structure.png +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svf-tools",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1195",
|
|
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": {
|
|
@@ -114,7 +114,7 @@ public:
|
|
|
114
114
|
/// Return the internal index if addr is an address otherwise return the value of idx
|
|
115
115
|
inline u32_t getIDFromAddr(u32_t addr)
|
|
116
116
|
{
|
|
117
|
-
return _freedAddrs.count(addr) ? AddressValue::getInternalID(
|
|
117
|
+
return _freedAddrs.count(addr) ? AddressValue::getInternalID(BlackHoleObjAddr) : AddressValue::getInternalID(addr);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
AbstractState&operator=(const AbstractState&rhs)
|
|
@@ -187,9 +187,9 @@ public:
|
|
|
187
187
|
return addr == NullMemAddr;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
static inline bool
|
|
190
|
+
static inline bool isBlackHoleObjAddr(u32_t addr)
|
|
191
191
|
{
|
|
192
|
-
return addr ==
|
|
192
|
+
return addr == BlackHoleObjAddr;
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
|
|
33
33
|
#define AddressMask 0x7f000000
|
|
34
34
|
#define FlippedAddressMask (AddressMask^0xffffffff)
|
|
35
|
-
// the address of
|
|
36
|
-
#define
|
|
35
|
+
// the address of BlackHole object, getVirtualMemAddress(2);
|
|
36
|
+
#define BlackHoleObjAddr 0x7f000000 + 2
|
|
37
37
|
// the address of NullMem, getVirtualMemAddress(0);
|
|
38
38
|
#define NullMemAddr 0x7f000000
|
|
39
39
|
|
|
@@ -74,43 +74,23 @@ public:
|
|
|
74
74
|
*/
|
|
75
75
|
void handleExtAPI(const CallICFGNode *call);
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
* @brief Handles the strcpy API call.
|
|
79
|
-
* @param call Pointer to the call ICFG node.
|
|
80
|
-
*/
|
|
81
|
-
void handleStrcpy(const CallICFGNode *call);
|
|
77
|
+
// --- Shared primitives used by string/memory handlers ---
|
|
82
78
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
79
|
+
/// Get the byte size of each element for a pointer/array variable.
|
|
80
|
+
u32_t getElementSize(AbstractState& as, const SVFVar* var);
|
|
81
|
+
|
|
82
|
+
/// Check if an interval length is usable (not bottom, not unbounded).
|
|
83
|
+
static bool isValidLength(const IntervalValue& len);
|
|
84
|
+
|
|
85
|
+
/// Calculate the length of a null-terminated string in abstract state.
|
|
89
86
|
IntervalValue getStrlen(AbstractState& as, const SVF::SVFVar *strValue);
|
|
90
87
|
|
|
91
|
-
|
|
92
|
-
* @brief Handles the strcat API call.
|
|
93
|
-
* @param call Pointer to the call ICFG node.
|
|
94
|
-
*/
|
|
95
|
-
void handleStrcat(const SVF::CallICFGNode *call);
|
|
88
|
+
// --- String/memory operation handlers ---
|
|
96
89
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
* @param dst Pointer to the destination SVF variable.
|
|
101
|
-
* @param src Pointer to the source SVF variable.
|
|
102
|
-
* @param len The interval value representing the length to copy.
|
|
103
|
-
* @param start_idx The starting index for copying.
|
|
104
|
-
*/
|
|
90
|
+
void handleStrcpy(const CallICFGNode *call);
|
|
91
|
+
void handleStrcat(const CallICFGNode *call);
|
|
92
|
+
void handleStrncat(const CallICFGNode *call);
|
|
105
93
|
void handleMemcpy(AbstractState& as, const SVF::SVFVar *dst, const SVF::SVFVar *src, IntervalValue len, u32_t start_idx);
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* @brief Handles the memset API call.
|
|
109
|
-
* @param as Reference to the abstract state.
|
|
110
|
-
* @param dst Pointer to the destination SVF variable.
|
|
111
|
-
* @param elem The interval value representing the element to set.
|
|
112
|
-
* @param len The interval value representing the length to set.
|
|
113
|
-
*/
|
|
114
94
|
void handleMemset(AbstractState& as, const SVFVar* dst, IntervalValue elem, IntervalValue len);
|
|
115
95
|
|
|
116
96
|
/**
|
|
@@ -36,6 +36,8 @@
|
|
|
36
36
|
#include "Util/SVFBugReport.h"
|
|
37
37
|
#include "Util/SVFStat.h"
|
|
38
38
|
#include "Graphs/SCC.h"
|
|
39
|
+
#include "Graphs/CallGraph.h"
|
|
40
|
+
#include <deque>
|
|
39
41
|
|
|
40
42
|
namespace SVF
|
|
41
43
|
{
|
|
@@ -144,6 +146,13 @@ public:
|
|
|
144
146
|
/// Program entry
|
|
145
147
|
void analyse();
|
|
146
148
|
|
|
149
|
+
/// Analyze all entry points (functions without callers)
|
|
150
|
+
void analyzeFromAllProgEntries();
|
|
151
|
+
|
|
152
|
+
/// Get all entry point functions (functions without callers)
|
|
153
|
+
std::deque<const FunObjVar*> collectProgEntryFuns();
|
|
154
|
+
|
|
155
|
+
|
|
147
156
|
static AbstractInterpretation& getAEInstance()
|
|
148
157
|
{
|
|
149
158
|
static AbstractInterpretation instance;
|
|
@@ -218,14 +227,14 @@ private:
|
|
|
218
227
|
*
|
|
219
228
|
* @param cycle WTOCycle which has weak topo order of basic blocks and nested cycles
|
|
220
229
|
*/
|
|
221
|
-
virtual void handleLoopOrRecursion(const ICFGCycleWTO* cycle);
|
|
230
|
+
virtual void handleLoopOrRecursion(const ICFGCycleWTO* cycle, const CallICFGNode* caller = nullptr);
|
|
222
231
|
|
|
223
232
|
/**
|
|
224
233
|
* Handle a function using worklist algorithm
|
|
225
234
|
*
|
|
226
235
|
* @param funEntry The entry node of the function to handle
|
|
227
236
|
*/
|
|
228
|
-
void handleFunction(const ICFGNode* funEntry);
|
|
237
|
+
void handleFunction(const ICFGNode* funEntry, const CallICFGNode* caller = nullptr);
|
|
229
238
|
|
|
230
239
|
/**
|
|
231
240
|
* Handle an ICFG node by merging states and processing statements
|
|
@@ -322,9 +331,9 @@ private:
|
|
|
322
331
|
AEAPI* api{nullptr};
|
|
323
332
|
|
|
324
333
|
ICFG* icfg;
|
|
334
|
+
CallGraph* callGraph;
|
|
325
335
|
AEStat* stat;
|
|
326
336
|
|
|
327
|
-
std::vector<const CallICFGNode*> callSiteStack;
|
|
328
337
|
Map<const FunObjVar*, const ICFGWTO*> funcToWTO;
|
|
329
338
|
Set<std::pair<const CallICFGNode*, NodeID>> nonRecursiveCallSites;
|
|
330
339
|
Set<const FunObjVar*> recursiveFuns;
|
|
@@ -358,6 +367,7 @@ private:
|
|
|
358
367
|
Map<std::string, std::function<void(const CallICFGNode*)>> func_map;
|
|
359
368
|
|
|
360
369
|
Map<const ICFGNode*, AbstractState> abstractTrace; // abstract states immediately after nodes
|
|
370
|
+
Set<const ICFGNode*> allAnalyzedNodes; // All nodes ever analyzed (across all entry points)
|
|
361
371
|
std::string moduleName;
|
|
362
372
|
|
|
363
373
|
std::vector<std::unique_ptr<AEDetector>> detectors;
|
|
@@ -367,7 +367,7 @@ void BufOverflowDetector::updateGepObjOffsetFromBase(AbstractState& as, SVF::Add
|
|
|
367
367
|
}
|
|
368
368
|
else
|
|
369
369
|
{
|
|
370
|
-
assert(AbstractState::
|
|
370
|
+
assert(AbstractState::isBlackHoleObjAddr(gepAddr) && "GEP object is neither a GepObjVar nor an invalid memory address");
|
|
371
371
|
}
|
|
372
372
|
}
|
|
373
373
|
}
|
|
@@ -398,7 +398,7 @@ void BufOverflowDetector::updateGepObjOffsetFromBase(AbstractState& as, SVF::Add
|
|
|
398
398
|
}
|
|
399
399
|
else
|
|
400
400
|
{
|
|
401
|
-
assert(AbstractState::
|
|
401
|
+
assert(AbstractState::isBlackHoleObjAddr(gepAddr) && "GEP object is neither a GepObjVar nor an invalid memory address");
|
|
402
402
|
}
|
|
403
403
|
}
|
|
404
404
|
}
|
|
@@ -479,7 +479,23 @@ bool BufOverflowDetector::canSafelyAccessMemory(AbstractState& as, const SVF::SV
|
|
|
479
479
|
SVFIR* svfir = PAG::getPAG();
|
|
480
480
|
NodeID value_id = value->getId();
|
|
481
481
|
|
|
482
|
-
|
|
482
|
+
// Lazy initialization for uninitialized pointer parameters in multi-entry analysis.
|
|
483
|
+
// When analyzing a function as an entry point (e.g., not called from main),
|
|
484
|
+
// pointer parameters may not have been initialized via AddrStmt.
|
|
485
|
+
//
|
|
486
|
+
// Example:
|
|
487
|
+
// void process_buffer(char* buf, int len) {
|
|
488
|
+
// buf[0] = 'a'; // accessing buf
|
|
489
|
+
// }
|
|
490
|
+
// When analyzing process_buffer as an entry point, 'buf' is a function parameter
|
|
491
|
+
// with no AddrStmt, so it has no address information in the abstract state.
|
|
492
|
+
// We lazily initialize it to point to the black hole object (BlkPtr), representing
|
|
493
|
+
// an unknown but valid memory location. This allows the analysis to continue
|
|
494
|
+
// while being conservatively sound.
|
|
495
|
+
if (!as[value_id].isAddr())
|
|
496
|
+
{
|
|
497
|
+
as[value_id] = AddressValue(BlackHoleObjAddr);
|
|
498
|
+
}
|
|
483
499
|
for (const auto& addr : as[value_id].getAddrs())
|
|
484
500
|
{
|
|
485
501
|
NodeID objId = as.getIDFromAddr(addr);
|
|
@@ -687,7 +703,7 @@ bool NullptrDerefDetector::canSafelyDerefPtr(AbstractState& as, const SVFVar* va
|
|
|
687
703
|
for (const auto &addr: AbsVal.getAddrs())
|
|
688
704
|
{
|
|
689
705
|
// if the addr itself is invalid mem, report unsafe
|
|
690
|
-
if (AbstractState::
|
|
706
|
+
if (AbstractState::isBlackHoleObjAddr(addr))
|
|
691
707
|
return false;
|
|
692
708
|
// if nullptr is detected, return unsafe
|
|
693
709
|
else if (AbstractState::isNullMem(addr))
|
|
@@ -272,60 +272,19 @@ void AbsExtAPI::initExtFunMap()
|
|
|
272
272
|
|
|
273
273
|
auto sse_strlen = [&](const CallICFGNode *callNode)
|
|
274
274
|
{
|
|
275
|
-
// check the arg size
|
|
276
275
|
if (callNode->arg_size() < 1) return;
|
|
277
|
-
const SVFVar* strValue = callNode->getArgument(0);
|
|
278
276
|
AbstractState& as = getAbsStateFromTrace(callNode);
|
|
279
|
-
NodeID value_id = strValue->getId();
|
|
280
277
|
u32_t lhsId = callNode->getRetICFGNode()->getActualRet()->getId();
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
else
|
|
290
|
-
{
|
|
291
|
-
const ICFGNode* addrNode = svfir->getBaseObject(objId)->getICFGNode();
|
|
292
|
-
for (const SVFStmt* stmt2: addrNode->getSVFStmts())
|
|
293
|
-
{
|
|
294
|
-
if (const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt2))
|
|
295
|
-
{
|
|
296
|
-
dst_size = as.getAllocaInstByteSize(addrStmt);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
u32_t len = 0;
|
|
302
|
-
NodeID dstid = strValue->getId();
|
|
303
|
-
if (as.inVarToAddrsTable(dstid))
|
|
304
|
-
{
|
|
305
|
-
for (u32_t index = 0; index < dst_size; index++)
|
|
306
|
-
{
|
|
307
|
-
AbstractValue expr0 =
|
|
308
|
-
as.getGepObjAddrs(dstid, IntervalValue(index));
|
|
309
|
-
AbstractValue val;
|
|
310
|
-
for (const auto &addr: expr0.getAddrs())
|
|
311
|
-
{
|
|
312
|
-
val.join_with(as.load(addr));
|
|
313
|
-
}
|
|
314
|
-
if (val.getInterval().is_numeral() && (char) val.getInterval().getIntNumeral() == '\0')
|
|
315
|
-
{
|
|
316
|
-
break;
|
|
317
|
-
}
|
|
318
|
-
++len;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
if (len == 0)
|
|
322
|
-
{
|
|
323
|
-
as[lhsId] = IntervalValue((s64_t)0, (s64_t)Options::MaxFieldLimit());
|
|
324
|
-
}
|
|
278
|
+
// strlen/wcslen return the number of characters (not bytes).
|
|
279
|
+
// getStrlen returns byte-scaled length (len * elemSize) for use
|
|
280
|
+
// by memcpy/strcpy. Here we need the raw character count, so
|
|
281
|
+
// divide back by elemSize.
|
|
282
|
+
IntervalValue byteLen = getStrlen(as, callNode->getArgument(0));
|
|
283
|
+
u32_t elemSize = getElementSize(as, callNode->getArgument(0));
|
|
284
|
+
if (byteLen.is_numeral() && elemSize > 1)
|
|
285
|
+
as[lhsId] = IntervalValue(byteLen.getIntNumeral() / (s64_t)elemSize);
|
|
325
286
|
else
|
|
326
|
-
|
|
327
|
-
as[lhsId] = IntervalValue(len);
|
|
328
|
-
}
|
|
287
|
+
as[lhsId] = byteLen;
|
|
329
288
|
};
|
|
330
289
|
func_map["strlen"] = sse_strlen;
|
|
331
290
|
func_map["wcslen"] = sse_strlen;
|
|
@@ -350,7 +309,7 @@ void AbsExtAPI::initExtFunMap()
|
|
|
350
309
|
const u32_t freePtr = callNode->getArgument(0)->getId();
|
|
351
310
|
for (auto addr: as[freePtr].getAddrs())
|
|
352
311
|
{
|
|
353
|
-
if (AbstractState::
|
|
312
|
+
if (AbstractState::isBlackHoleObjAddr(addr))
|
|
354
313
|
{
|
|
355
314
|
// Detected a double free — the address has already been freed.
|
|
356
315
|
// No action is taken at this point.
|
|
@@ -480,7 +439,13 @@ void AbsExtAPI::handleExtAPI(const CallICFGNode *call)
|
|
|
480
439
|
}
|
|
481
440
|
else if (extType == STRCAT)
|
|
482
441
|
{
|
|
483
|
-
|
|
442
|
+
// Both strcat and strncat are annotated as STRCAT.
|
|
443
|
+
// Distinguish by name: strncat/wcsncat contain "ncat".
|
|
444
|
+
const std::string& name = fun->getName();
|
|
445
|
+
if (name.find("ncat") != std::string::npos)
|
|
446
|
+
handleStrncat(call);
|
|
447
|
+
else
|
|
448
|
+
handleStrcat(call);
|
|
484
449
|
}
|
|
485
450
|
else
|
|
486
451
|
{
|
|
@@ -489,21 +454,50 @@ void AbsExtAPI::handleExtAPI(const CallICFGNode *call)
|
|
|
489
454
|
return;
|
|
490
455
|
}
|
|
491
456
|
|
|
492
|
-
|
|
457
|
+
// ===----------------------------------------------------------------------===//
|
|
458
|
+
// Shared primitives for string/memory handlers
|
|
459
|
+
// ===----------------------------------------------------------------------===//
|
|
460
|
+
|
|
461
|
+
/// Get the byte size of each element for a pointer/array variable.
|
|
462
|
+
/// Shared by handleMemcpy, handleMemset, and getStrlen to avoid duplication.
|
|
463
|
+
u32_t AbsExtAPI::getElementSize(AbstractState& as, const SVFVar* var)
|
|
493
464
|
{
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
465
|
+
if (var->getType()->isArrayTy())
|
|
466
|
+
{
|
|
467
|
+
return SVFUtil::dyn_cast<SVFArrayType>(var->getType())
|
|
468
|
+
->getTypeOfElement()->getByteSize();
|
|
469
|
+
}
|
|
470
|
+
if (var->getType()->isPointerTy())
|
|
471
|
+
{
|
|
472
|
+
if (const SVFType* elemType = as.getPointeeElement(var->getId()))
|
|
473
|
+
{
|
|
474
|
+
if (elemType->isArrayTy())
|
|
475
|
+
return SVFUtil::dyn_cast<SVFArrayType>(elemType)
|
|
476
|
+
->getTypeOfElement()->getByteSize();
|
|
477
|
+
return elemType->getByteSize();
|
|
478
|
+
}
|
|
479
|
+
return 1;
|
|
480
|
+
}
|
|
481
|
+
assert(false && "unsupported type for element size");
|
|
482
|
+
return 1;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/// Check if an interval length is usable for memory operations.
|
|
486
|
+
/// Returns false for bottom (no information) or unbounded lower bound
|
|
487
|
+
/// (cannot determine a concrete start for iteration).
|
|
488
|
+
bool AbsExtAPI::isValidLength(const IntervalValue& len)
|
|
489
|
+
{
|
|
490
|
+
return !len.isBottom() && !len.lb().is_minus_infinity();
|
|
502
491
|
}
|
|
503
492
|
|
|
493
|
+
/// Calculate the length of a null-terminated string in abstract state.
|
|
494
|
+
/// Scans memory from the base of strValue looking for a '\0' byte.
|
|
495
|
+
/// Returns an IntervalValue: exact length if '\0' found, otherwise [0, MaxFieldLimit].
|
|
504
496
|
IntervalValue AbsExtAPI::getStrlen(AbstractState& as, const SVF::SVFVar *strValue)
|
|
505
497
|
{
|
|
506
498
|
NodeID value_id = strValue->getId();
|
|
499
|
+
|
|
500
|
+
// Step 1: determine the buffer size (in bytes) backing this pointer
|
|
507
501
|
u32_t dst_size = 0;
|
|
508
502
|
for (const auto& addr : as[value_id].getAddrs())
|
|
509
503
|
{
|
|
@@ -524,8 +518,9 @@ IntervalValue AbsExtAPI::getStrlen(AbstractState& as, const SVF::SVFVar *strValu
|
|
|
524
518
|
}
|
|
525
519
|
}
|
|
526
520
|
}
|
|
521
|
+
|
|
522
|
+
// Step 2: scan for '\0' terminator
|
|
527
523
|
u32_t len = 0;
|
|
528
|
-
u32_t elemSize = 1;
|
|
529
524
|
if (as.inVarToAddrsTable(value_id))
|
|
530
525
|
{
|
|
531
526
|
for (u32_t index = 0; index < dst_size; index++)
|
|
@@ -537,188 +532,153 @@ IntervalValue AbsExtAPI::getStrlen(AbstractState& as, const SVF::SVFVar *strValu
|
|
|
537
532
|
{
|
|
538
533
|
val.join_with(as.load(addr));
|
|
539
534
|
}
|
|
540
|
-
if (val.getInterval().is_numeral() &&
|
|
535
|
+
if (val.getInterval().is_numeral() &&
|
|
536
|
+
(char) val.getInterval().getIntNumeral() == '\0')
|
|
541
537
|
{
|
|
542
538
|
break;
|
|
543
539
|
}
|
|
544
540
|
++len;
|
|
545
541
|
}
|
|
546
|
-
if (strValue->getType()->isArrayTy())
|
|
547
|
-
{
|
|
548
|
-
elemSize = SVFUtil::dyn_cast<SVFArrayType>(strValue->getType())->getTypeOfElement()->getByteSize();
|
|
549
|
-
}
|
|
550
|
-
else if (strValue->getType()->isPointerTy())
|
|
551
|
-
{
|
|
552
|
-
if (const SVFType* elemType = as.getPointeeElement(value_id))
|
|
553
|
-
{
|
|
554
|
-
if (elemType->isArrayTy())
|
|
555
|
-
elemSize = SVFUtil::dyn_cast<SVFArrayType>(elemType)->getTypeOfElement()->getByteSize();
|
|
556
|
-
else
|
|
557
|
-
elemSize = elemType->getByteSize();
|
|
558
|
-
}
|
|
559
|
-
else
|
|
560
|
-
{
|
|
561
|
-
elemSize = 1;
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
else
|
|
565
|
-
{
|
|
566
|
-
assert(false && "we cannot support this type");
|
|
567
|
-
}
|
|
568
542
|
}
|
|
543
|
+
|
|
544
|
+
// Step 3: scale by element size and return
|
|
545
|
+
u32_t elemSize = getElementSize(as, strValue);
|
|
569
546
|
if (len == 0)
|
|
570
|
-
{
|
|
571
547
|
return IntervalValue((s64_t)0, (s64_t)Options::MaxFieldLimit());
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
548
|
+
return IntervalValue(len * elemSize);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// ===----------------------------------------------------------------------===//
|
|
552
|
+
// String/memory operation handlers
|
|
553
|
+
// ===----------------------------------------------------------------------===//
|
|
554
|
+
|
|
555
|
+
/// strcpy(dst, src): copy all of src (including '\0') into dst.
|
|
556
|
+
/// Covers: strcpy, __strcpy_chk, stpcpy, wcscpy, __wcscpy_chk
|
|
557
|
+
void AbsExtAPI::handleStrcpy(const CallICFGNode *call)
|
|
558
|
+
{
|
|
559
|
+
AbstractState& as = getAbsStateFromTrace(call);
|
|
560
|
+
const SVFVar* dst = call->getArgument(0);
|
|
561
|
+
const SVFVar* src = call->getArgument(1);
|
|
562
|
+
IntervalValue srcLen = getStrlen(as, src);
|
|
563
|
+
// no need to -1, since srcLen includes up to (but not past) '\0'
|
|
564
|
+
if (!isValidLength(srcLen)) return;
|
|
565
|
+
handleMemcpy(as, dst, src, srcLen, 0);
|
|
577
566
|
}
|
|
578
567
|
|
|
568
|
+
/// strcat(dst, src): append all of src after the end of dst.
|
|
569
|
+
/// Covers: strcat, __strcat_chk, wcscat, __wcscat_chk
|
|
570
|
+
void AbsExtAPI::handleStrcat(const CallICFGNode *call)
|
|
571
|
+
{
|
|
572
|
+
AbstractState& as = getAbsStateFromTrace(call);
|
|
573
|
+
const SVFVar* dst = call->getArgument(0);
|
|
574
|
+
const SVFVar* src = call->getArgument(1);
|
|
575
|
+
IntervalValue dstLen = getStrlen(as, dst);
|
|
576
|
+
IntervalValue srcLen = getStrlen(as, src);
|
|
577
|
+
if (!isValidLength(dstLen)) return;
|
|
578
|
+
handleMemcpy(as, dst, src, srcLen, dstLen.lb().getIntNumeral());
|
|
579
|
+
}
|
|
579
580
|
|
|
580
|
-
|
|
581
|
+
/// strncat(dst, src, n): append at most n bytes of src after the end of dst.
|
|
582
|
+
/// Covers: strncat, __strncat_chk, wcsncat, __wcsncat_chk
|
|
583
|
+
void AbsExtAPI::handleStrncat(const CallICFGNode *call)
|
|
581
584
|
{
|
|
582
|
-
// __strcat_chk, strcat, __wcscat_chk, wcscat, __strncat_chk, strncat, __wcsncat_chk, wcsncat
|
|
583
|
-
// to check it is strcat group or strncat group
|
|
584
585
|
AbstractState& as = getAbsStateFromTrace(call);
|
|
585
|
-
const
|
|
586
|
-
const
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
const SVFVar* arg1Val = call->getArgument(1);
|
|
592
|
-
IntervalValue strLen0 = getStrlen(as, arg0Val);
|
|
593
|
-
IntervalValue strLen1 = getStrlen(as, arg1Val);
|
|
594
|
-
IntervalValue totalLen = strLen0 + strLen1;
|
|
595
|
-
handleMemcpy(as, arg0Val, arg1Val, strLen1, strLen0.lb().getIntNumeral());
|
|
596
|
-
// do memcpy
|
|
597
|
-
}
|
|
598
|
-
else if (std::find(strncatGroup.begin(), strncatGroup.end(), fun->getName()) != strncatGroup.end())
|
|
599
|
-
{
|
|
600
|
-
const SVFVar* arg0Val = call->getArgument(0);
|
|
601
|
-
const SVFVar* arg1Val = call->getArgument(1);
|
|
602
|
-
const SVFVar* arg2Val = call->getArgument(2);
|
|
603
|
-
IntervalValue arg2Num = as[arg2Val->getId()].getInterval();
|
|
604
|
-
IntervalValue strLen0 = getStrlen(as, arg0Val);
|
|
605
|
-
IntervalValue totalLen = strLen0 + arg2Num;
|
|
606
|
-
handleMemcpy(as, arg0Val, arg1Val, arg2Num, strLen0.lb().getIntNumeral());
|
|
607
|
-
// do memcpy
|
|
608
|
-
}
|
|
609
|
-
else
|
|
610
|
-
{
|
|
611
|
-
assert(false && "unknown strcat function, please add it to strcatGroup or strncatGroup");
|
|
612
|
-
}
|
|
586
|
+
const SVFVar* dst = call->getArgument(0);
|
|
587
|
+
const SVFVar* src = call->getArgument(1);
|
|
588
|
+
IntervalValue n = as[call->getArgument(2)->getId()].getInterval();
|
|
589
|
+
IntervalValue dstLen = getStrlen(as, dst);
|
|
590
|
+
if (!isValidLength(dstLen)) return;
|
|
591
|
+
handleMemcpy(as, dst, src, n, dstLen.lb().getIntNumeral());
|
|
613
592
|
}
|
|
614
593
|
|
|
615
|
-
|
|
594
|
+
/// Core memcpy: copy `len` bytes from src to dst starting at dst[start_idx].
|
|
595
|
+
void AbsExtAPI::handleMemcpy(AbstractState& as, const SVF::SVFVar *dst,
|
|
596
|
+
const SVF::SVFVar *src, IntervalValue len,
|
|
597
|
+
u32_t start_idx)
|
|
616
598
|
{
|
|
617
|
-
|
|
599
|
+
if (!isValidLength(len)) return;
|
|
600
|
+
|
|
601
|
+
u32_t dstId = dst->getId();
|
|
618
602
|
u32_t srcId = src->getId();
|
|
619
|
-
u32_t elemSize =
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
elemSize = SVFUtil::dyn_cast<SVFArrayType>(dst->getType())->getTypeOfElement()->getByteSize();
|
|
623
|
-
}
|
|
624
|
-
// memcpy(i32*, i32*, 40)
|
|
625
|
-
else if (dst->getType()->isPointerTy())
|
|
626
|
-
{
|
|
627
|
-
if (const SVFType* elemType = as.getPointeeElement(dstId))
|
|
628
|
-
{
|
|
629
|
-
if (elemType->isArrayTy())
|
|
630
|
-
elemSize = SVFUtil::dyn_cast<SVFArrayType>(elemType)->getTypeOfElement()->getByteSize();
|
|
631
|
-
else
|
|
632
|
-
elemSize = elemType->getByteSize();
|
|
633
|
-
}
|
|
634
|
-
else
|
|
635
|
-
{
|
|
636
|
-
elemSize = 1;
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
else
|
|
640
|
-
{
|
|
641
|
-
assert(false && "we cannot support this type");
|
|
642
|
-
}
|
|
643
|
-
u32_t size = std::min((u32_t)Options::MaxFieldLimit(), (u32_t) len.lb().getIntNumeral());
|
|
603
|
+
u32_t elemSize = getElementSize(as, dst);
|
|
604
|
+
u32_t size = std::min((u32_t)Options::MaxFieldLimit(),
|
|
605
|
+
(u32_t)len.lb().getIntNumeral());
|
|
644
606
|
u32_t range_val = size / elemSize;
|
|
645
|
-
|
|
607
|
+
|
|
608
|
+
if (!as.inVarToAddrsTable(srcId) || !as.inVarToAddrsTable(dstId))
|
|
609
|
+
return;
|
|
610
|
+
|
|
611
|
+
for (u32_t index = 0; index < range_val; index++)
|
|
646
612
|
{
|
|
647
|
-
|
|
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 &dstAddr: expr_dst.getAddrs())
|
|
648
618
|
{
|
|
649
|
-
|
|
650
|
-
AbstractValue expr_src =
|
|
651
|
-
as.getGepObjAddrs(srcId, IntervalValue(index));
|
|
652
|
-
AbstractValue expr_dst =
|
|
653
|
-
as.getGepObjAddrs(dstId, IntervalValue(index + start_idx));
|
|
654
|
-
for (const auto &dst: expr_dst.getAddrs())
|
|
619
|
+
for (const auto &srcAddr: expr_src.getAddrs())
|
|
655
620
|
{
|
|
656
|
-
|
|
621
|
+
u32_t objId = as.getIDFromAddr(srcAddr);
|
|
622
|
+
if (as.inAddrToValTable(objId) || as.inAddrToAddrsTable(objId))
|
|
657
623
|
{
|
|
658
|
-
|
|
659
|
-
if (as.inAddrToValTable(objId))
|
|
660
|
-
{
|
|
661
|
-
as.store(dst, as.load(src));
|
|
662
|
-
}
|
|
663
|
-
else if (as.inAddrToAddrsTable(objId))
|
|
664
|
-
{
|
|
665
|
-
as.store(dst, as.load(src));
|
|
666
|
-
}
|
|
624
|
+
as.store(dstAddr, as.load(srcAddr));
|
|
667
625
|
}
|
|
668
626
|
}
|
|
669
627
|
}
|
|
670
628
|
}
|
|
671
629
|
}
|
|
672
630
|
|
|
673
|
-
|
|
631
|
+
/// Core memset: fill dst with `elem` for `len` bytes.
|
|
632
|
+
/// Note: elemSize here uses the pointee type's full size (not array element size)
|
|
633
|
+
/// to match how LLVM memset/wmemset intrinsics measure `len`. For a pointer to
|
|
634
|
+
/// wchar_t[100], elemSize = sizeof(wchar_t[100]), so range_val reflects the
|
|
635
|
+
/// number of top-level GEP fields, not individual array elements.
|
|
636
|
+
void AbsExtAPI::handleMemset(AbstractState& as, const SVF::SVFVar *dst,
|
|
637
|
+
IntervalValue elem, IntervalValue len)
|
|
674
638
|
{
|
|
639
|
+
if (!isValidLength(len)) return;
|
|
640
|
+
|
|
675
641
|
u32_t dstId = dst->getId();
|
|
676
|
-
u32_t size = std::min((u32_t)Options::MaxFieldLimit(), (u32_t) len.lb().getIntNumeral());
|
|
677
642
|
u32_t elemSize = 1;
|
|
678
643
|
if (dst->getType()->isArrayTy())
|
|
679
644
|
{
|
|
680
|
-
elemSize = SVFUtil::dyn_cast<SVFArrayType>(dst->getType())
|
|
645
|
+
elemSize = SVFUtil::dyn_cast<SVFArrayType>(dst->getType())
|
|
646
|
+
->getTypeOfElement()->getByteSize();
|
|
681
647
|
}
|
|
682
648
|
else if (dst->getType()->isPointerTy())
|
|
683
649
|
{
|
|
684
650
|
if (const SVFType* elemType = as.getPointeeElement(dstId))
|
|
685
|
-
{
|
|
686
651
|
elemSize = elemType->getByteSize();
|
|
687
|
-
}
|
|
688
652
|
else
|
|
689
|
-
{
|
|
690
653
|
elemSize = 1;
|
|
691
|
-
}
|
|
692
654
|
}
|
|
693
655
|
else
|
|
694
656
|
{
|
|
695
|
-
assert(false && "
|
|
657
|
+
assert(false && "unsupported type for element size");
|
|
696
658
|
}
|
|
697
|
-
|
|
659
|
+
u32_t size = std::min((u32_t)Options::MaxFieldLimit(),
|
|
660
|
+
(u32_t)len.lb().getIntNumeral());
|
|
698
661
|
u32_t range_val = size / elemSize;
|
|
662
|
+
|
|
699
663
|
for (u32_t index = 0; index < range_val; index++)
|
|
700
664
|
{
|
|
701
|
-
|
|
702
|
-
|
|
665
|
+
if (!as.inVarToAddrsTable(dstId))
|
|
666
|
+
break;
|
|
667
|
+
AbstractValue lhs_gep = as.getGepObjAddrs(dstId, IntervalValue(index));
|
|
668
|
+
for (const auto &addr: lhs_gep.getAddrs())
|
|
703
669
|
{
|
|
704
|
-
|
|
705
|
-
|
|
670
|
+
u32_t objId = as.getIDFromAddr(addr);
|
|
671
|
+
if (as.inAddrToValTable(objId))
|
|
706
672
|
{
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
else
|
|
715
|
-
{
|
|
716
|
-
as.store(addr, elem);
|
|
717
|
-
}
|
|
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);
|
|
718
680
|
}
|
|
719
681
|
}
|
|
720
|
-
else
|
|
721
|
-
break;
|
|
722
682
|
}
|
|
723
683
|
}
|
|
724
684
|
|