svf-tools 1.0.697 → 1.0.699
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/AbstractExecution/IntervalExeState.h +38 -17
- package/svf/include/AbstractExecution/IntervalValue.h +12 -2
- package/svf/include/SABER/FileChecker.h +0 -2
- package/svf/include/SABER/LeakChecker.h +0 -2
- package/svf/include/SABER/ProgSlice.h +3 -0
- package/svf/include/SABER/SrcSnkDDA.h +3 -2
- package/svf/include/Util/SVFBugReport.h +424 -0
- package/svf/lib/AbstractExecution/SVFIR2ItvExeState.cpp +9 -9
- package/svf/lib/SABER/DoubleFreeChecker.cpp +5 -5
- package/svf/lib/SABER/FileChecker.cpp +9 -18
- package/svf/lib/SABER/LeakChecker.cpp +10 -19
- package/svf/lib/SABER/ProgSlice.cpp +16 -1
- package/svf/lib/SABER/SrcSnkDDA.cpp +0 -1
- package/svf/lib/Util/SVFBugReport.cpp +411 -0
- package/svf-llvm/lib/LLVMUtil.cpp +5 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svf-tools",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.699",
|
|
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": {
|
|
@@ -140,11 +140,11 @@ public:
|
|
|
140
140
|
|
|
141
141
|
VAddrs &getVAddrs(u32_t id) override
|
|
142
142
|
{
|
|
143
|
-
auto it =
|
|
144
|
-
if (it !=
|
|
143
|
+
auto it = _varToVAddrs.find(id);
|
|
144
|
+
if (it != _varToVAddrs.end())
|
|
145
145
|
return it->second;
|
|
146
146
|
else
|
|
147
|
-
return _varToVAddrs[id];
|
|
147
|
+
return globalES._varToVAddrs[id];
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
inline bool inVarToIValTable(u32_t id) const
|
|
@@ -201,14 +201,24 @@ public:
|
|
|
201
201
|
/// [], call getValueExpr()
|
|
202
202
|
inline IntervalValue &operator[](u32_t varId)
|
|
203
203
|
{
|
|
204
|
-
auto
|
|
205
|
-
if
|
|
204
|
+
auto localIt = _varToItvVal.find(varId);
|
|
205
|
+
if(localIt != _varToItvVal.end())
|
|
206
|
+
return localIt->second;
|
|
207
|
+
else
|
|
206
208
|
{
|
|
207
|
-
return
|
|
209
|
+
return globalES._varToItvVal[varId];
|
|
208
210
|
}
|
|
209
|
-
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
inline void cpyItvToLocal(u32_t varId)
|
|
214
|
+
{
|
|
215
|
+
auto localIt = _varToItvVal.find(varId);
|
|
216
|
+
// local already have varId
|
|
217
|
+
if (localIt != _varToItvVal.end()) return;
|
|
218
|
+
auto globIt = globalES._varToItvVal.find(varId);
|
|
219
|
+
if (globIt != globalES._varToItvVal.end())
|
|
210
220
|
{
|
|
211
|
-
|
|
221
|
+
_varToItvVal[varId] = globIt->second;
|
|
212
222
|
}
|
|
213
223
|
}
|
|
214
224
|
|
|
@@ -370,16 +380,29 @@ public:
|
|
|
370
380
|
|
|
371
381
|
static bool lessThanVarToValMap(const VarToValMap &lhs, const VarToValMap &rhs)
|
|
372
382
|
{
|
|
383
|
+
if (lhs.empty()) return !rhs.empty();
|
|
373
384
|
for (const auto &item: lhs)
|
|
374
385
|
{
|
|
375
386
|
auto it = rhs.find(item.first);
|
|
387
|
+
if (it == rhs.end()) return false;
|
|
376
388
|
// judge from expr id
|
|
377
|
-
if (
|
|
378
|
-
{
|
|
379
|
-
return !item.second.geq(it->second);
|
|
380
|
-
}
|
|
389
|
+
if (item.second.geq(it->second)) return false;
|
|
381
390
|
}
|
|
382
|
-
return
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// lhs >= rhs
|
|
395
|
+
static bool geqVarToValMap(const VarToValMap &lhs, const VarToValMap &rhs)
|
|
396
|
+
{
|
|
397
|
+
if (rhs.empty()) return true;
|
|
398
|
+
for (const auto &item: rhs)
|
|
399
|
+
{
|
|
400
|
+
auto it = lhs.find(item.first);
|
|
401
|
+
if (it == lhs.end()) return false;
|
|
402
|
+
// judge from expr id
|
|
403
|
+
if (!it->second.geq(item.second)) return false;
|
|
404
|
+
}
|
|
405
|
+
return true;
|
|
383
406
|
}
|
|
384
407
|
|
|
385
408
|
bool operator==(const IntervalExeState &rhs) const
|
|
@@ -395,15 +418,13 @@ public:
|
|
|
395
418
|
|
|
396
419
|
bool operator<(const IntervalExeState &rhs) const
|
|
397
420
|
{
|
|
398
|
-
|
|
399
|
-
return (lessThanVarToValMap(_varToItvVal, rhs.getVarToVal()) ||
|
|
400
|
-
lessThanVarToValMap(_locToItvVal, rhs.getLocToVal()));
|
|
421
|
+
return !(*this >= rhs);
|
|
401
422
|
}
|
|
402
423
|
|
|
403
424
|
|
|
404
425
|
bool operator>=(const IntervalExeState &rhs) const
|
|
405
426
|
{
|
|
406
|
-
return
|
|
427
|
+
return geqVarToValMap(_varToItvVal, rhs.getVarToVal()) && geqVarToValMap(_locToItvVal, rhs.getLocToVal());
|
|
407
428
|
}
|
|
408
429
|
|
|
409
430
|
void clear()
|
|
@@ -438,9 +438,19 @@ public:
|
|
|
438
438
|
}
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
-
std::string toString() const
|
|
441
|
+
const std::string toString() const
|
|
442
442
|
{
|
|
443
|
-
|
|
443
|
+
std::string str;
|
|
444
|
+
std::stringstream rawStr(str);
|
|
445
|
+
if (this->isBottom())
|
|
446
|
+
{
|
|
447
|
+
rawStr << "⊥";
|
|
448
|
+
}
|
|
449
|
+
else
|
|
450
|
+
{
|
|
451
|
+
rawStr << "[" << lb().to_string() << ", " << ub().to_string() << "]";
|
|
452
|
+
}
|
|
453
|
+
return rawStr.str();
|
|
444
454
|
}
|
|
445
455
|
|
|
446
456
|
}; // end class IntervalValue
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
#include "Util/WorkList.h"
|
|
42
42
|
#include "Graphs/SVFG.h"
|
|
43
43
|
#include "Util/DPItem.h"
|
|
44
|
+
#include "Util/SVFBugReport.h"
|
|
44
45
|
|
|
45
46
|
namespace SVF
|
|
46
47
|
{
|
|
@@ -201,6 +202,8 @@ public:
|
|
|
201
202
|
}
|
|
202
203
|
/// Evaluate final condition
|
|
203
204
|
std::string evalFinalCond() const;
|
|
205
|
+
/// Add final condition to eventStack
|
|
206
|
+
void evalFinalCond2Event(GenericBug::EventStack &eventStack) const;
|
|
204
207
|
//@}
|
|
205
208
|
|
|
206
209
|
protected:
|
|
@@ -37,11 +37,11 @@
|
|
|
37
37
|
#ifndef SRCSNKANALYSIS_H_
|
|
38
38
|
#define SRCSNKANALYSIS_H_
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
#include "Util/GraphReachSolver.h"
|
|
42
40
|
#include "Graphs/SVFGOPT.h"
|
|
43
41
|
#include "SABER/ProgSlice.h"
|
|
44
42
|
#include "SABER/SaberSVFGBuilder.h"
|
|
43
|
+
#include "Util/GraphReachSolver.h"
|
|
44
|
+
#include "Util/SVFBugReport.h"
|
|
45
45
|
|
|
46
46
|
namespace SVF
|
|
47
47
|
{
|
|
@@ -77,6 +77,7 @@ protected:
|
|
|
77
77
|
SaberSVFGBuilder memSSA;
|
|
78
78
|
SVFG* svfg;
|
|
79
79
|
PTACallGraph* ptaCallGraph;
|
|
80
|
+
SVFBugReport report; /// Bug Reporter
|
|
80
81
|
|
|
81
82
|
public:
|
|
82
83
|
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
//===- SVFBugReport.h -- Base class for statistics---------------------------------//
|
|
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
|
+
// Created by JoelYang on 2023/4/19.
|
|
25
|
+
//
|
|
26
|
+
|
|
27
|
+
#ifndef SVF_BUGRECODER_H
|
|
28
|
+
#define SVF_BUGRECODER_H
|
|
29
|
+
|
|
30
|
+
#include <vector>
|
|
31
|
+
#include "SVFIR/SVFValue.h"
|
|
32
|
+
#include "SVFIR/SVFVariables.h"
|
|
33
|
+
#include "SVFIR/SVFStatements.h"
|
|
34
|
+
#include "Graphs/ICFGNode.h"
|
|
35
|
+
#include <string>
|
|
36
|
+
#include <map>
|
|
37
|
+
#include "Util/cJSON.h"
|
|
38
|
+
#include <set>
|
|
39
|
+
|
|
40
|
+
namespace SVF
|
|
41
|
+
{
|
|
42
|
+
|
|
43
|
+
/*!
|
|
44
|
+
* Bug Detector Recoder
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class GenericEvent
|
|
49
|
+
{
|
|
50
|
+
public:
|
|
51
|
+
enum EventType {Branch, Caller, CallSite, Loop, SourceInst};
|
|
52
|
+
|
|
53
|
+
protected:
|
|
54
|
+
EventType eventType;
|
|
55
|
+
|
|
56
|
+
public:
|
|
57
|
+
GenericEvent(EventType eventType): eventType(eventType) { };
|
|
58
|
+
virtual ~GenericEvent() = default;
|
|
59
|
+
|
|
60
|
+
inline EventType getEventType() const
|
|
61
|
+
{
|
|
62
|
+
return eventType;
|
|
63
|
+
}
|
|
64
|
+
virtual const std::string getEventDescription() const = 0;
|
|
65
|
+
virtual const std::string getFuncName() const = 0;
|
|
66
|
+
virtual const std::string getEventLoc() const = 0;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
class BranchEvent: public GenericEvent
|
|
70
|
+
{
|
|
71
|
+
/// branch statement and branch condition true or false
|
|
72
|
+
protected:
|
|
73
|
+
const SVFInstruction *branchInst;
|
|
74
|
+
bool branchSuccessFlg;
|
|
75
|
+
|
|
76
|
+
public:
|
|
77
|
+
BranchEvent(const SVFInstruction *branchInst, bool branchSuccessFlg):
|
|
78
|
+
GenericEvent(GenericEvent::Branch), branchInst(branchInst), branchSuccessFlg(branchSuccessFlg) { }
|
|
79
|
+
|
|
80
|
+
const std::string getEventDescription() const;
|
|
81
|
+
const std::string getFuncName() const;
|
|
82
|
+
const std::string getEventLoc() const;
|
|
83
|
+
|
|
84
|
+
/// ClassOf
|
|
85
|
+
static inline bool classof(const GenericEvent* event)
|
|
86
|
+
{
|
|
87
|
+
return event->getEventType() == GenericEvent::Branch;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
class CallSiteEvent: public GenericEvent
|
|
92
|
+
{
|
|
93
|
+
protected:
|
|
94
|
+
const CallICFGNode *callSite;
|
|
95
|
+
|
|
96
|
+
public:
|
|
97
|
+
CallSiteEvent(const CallICFGNode *callSite): GenericEvent(GenericEvent::CallSite), callSite(callSite) { }
|
|
98
|
+
const std::string getEventDescription() const;
|
|
99
|
+
const std::string getFuncName() const;
|
|
100
|
+
const std::string getEventLoc() const;
|
|
101
|
+
|
|
102
|
+
/// ClassOf
|
|
103
|
+
static inline bool classof(const GenericEvent* event)
|
|
104
|
+
{
|
|
105
|
+
return event->getEventType() == GenericEvent::CallSite;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
class SourceInstEvent : public GenericEvent
|
|
110
|
+
{
|
|
111
|
+
protected:
|
|
112
|
+
const SVFInstruction *sourceSVFInst;
|
|
113
|
+
|
|
114
|
+
public:
|
|
115
|
+
SourceInstEvent(const SVFInstruction *sourceSVFInst):
|
|
116
|
+
GenericEvent(GenericEvent::SourceInst), sourceSVFInst(sourceSVFInst) { }
|
|
117
|
+
|
|
118
|
+
const std::string getEventDescription() const;
|
|
119
|
+
const std::string getFuncName() const;
|
|
120
|
+
const std::string getEventLoc() const;
|
|
121
|
+
|
|
122
|
+
/// ClassOf
|
|
123
|
+
static inline bool classof(const GenericEvent* event)
|
|
124
|
+
{
|
|
125
|
+
return event->getEventType() == GenericEvent::SourceInst;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
class GenericBug
|
|
130
|
+
{
|
|
131
|
+
public:
|
|
132
|
+
typedef std::vector<const GenericEvent *> EventStack;
|
|
133
|
+
|
|
134
|
+
public:
|
|
135
|
+
enum BugType {FULLBUFOVERFLOW, PARTIALBUFOVERFLOW, NEVERFREE, PARTIALLEAK, DOUBLEFREE, FILENEVERCLOSE, FILEPARTIALCLOSE};
|
|
136
|
+
|
|
137
|
+
protected:
|
|
138
|
+
BugType bugType;
|
|
139
|
+
EventStack bugEventStack;
|
|
140
|
+
|
|
141
|
+
public:
|
|
142
|
+
/// note: should be initialized with a bugEventStack
|
|
143
|
+
GenericBug(BugType bugType, EventStack bugEventStack):
|
|
144
|
+
bugType(bugType), bugEventStack(bugEventStack)
|
|
145
|
+
{
|
|
146
|
+
assert(bugEventStack.size() != 0 && "bugEventStack should NOT be empty!");
|
|
147
|
+
}
|
|
148
|
+
virtual ~GenericBug() = default;
|
|
149
|
+
//GenericBug(const GenericBug &) = delete;
|
|
150
|
+
/// returns bug type
|
|
151
|
+
inline BugType getBugType() const
|
|
152
|
+
{
|
|
153
|
+
return bugType;
|
|
154
|
+
}
|
|
155
|
+
/// returns bug location as json format string
|
|
156
|
+
const std::string getLoc() const;
|
|
157
|
+
/// return bug source function name
|
|
158
|
+
const std::string getFuncName() const;
|
|
159
|
+
|
|
160
|
+
inline const EventStack& getEventStack() const
|
|
161
|
+
{
|
|
162
|
+
return bugEventStack;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
virtual cJSON *getBugDescription() const = 0;
|
|
166
|
+
virtual void printBugToTerminal() const = 0;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
class BufferOverflowBug: public GenericBug
|
|
170
|
+
{
|
|
171
|
+
protected:
|
|
172
|
+
s64_t allocLowerBound, allocUpperBound, accessLowerBound, accessUpperBound;
|
|
173
|
+
|
|
174
|
+
public:
|
|
175
|
+
BufferOverflowBug(GenericBug::BugType bugType, const EventStack &eventStack,
|
|
176
|
+
s64_t allocLowerBound, s64_t allocUpperBound,
|
|
177
|
+
s64_t accessLowerBound, s64_t accessUpperBound):
|
|
178
|
+
GenericBug(bugType, eventStack), allocLowerBound(allocLowerBound),
|
|
179
|
+
allocUpperBound(allocUpperBound), accessLowerBound(accessLowerBound),
|
|
180
|
+
accessUpperBound(accessUpperBound) { }
|
|
181
|
+
|
|
182
|
+
cJSON *getBugDescription() const;
|
|
183
|
+
void printBugToTerminal() const;
|
|
184
|
+
|
|
185
|
+
/// ClassOf
|
|
186
|
+
static inline bool classof(const GenericBug *bug)
|
|
187
|
+
{
|
|
188
|
+
return bug->getBugType() == GenericBug::PARTIALBUFOVERFLOW || bug->getBugType() == GenericBug::FULLBUFOVERFLOW;
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
class FullBufferOverflowBug: public BufferOverflowBug
|
|
193
|
+
{
|
|
194
|
+
public:
|
|
195
|
+
FullBufferOverflowBug(const EventStack &eventStack,
|
|
196
|
+
s64_t allocLowerBound, s64_t allocUpperBound,
|
|
197
|
+
s64_t accessLowerBound, s64_t accessUpperBound):
|
|
198
|
+
BufferOverflowBug(GenericBug::FULLBUFOVERFLOW, eventStack, allocLowerBound,
|
|
199
|
+
allocUpperBound, accessLowerBound, accessUpperBound) { }
|
|
200
|
+
|
|
201
|
+
/// ClassOf
|
|
202
|
+
static inline bool classof(const GenericBug *bug)
|
|
203
|
+
{
|
|
204
|
+
return bug->getBugType() == GenericBug::FULLBUFOVERFLOW;
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
class PartialBufferOverflowBug: public BufferOverflowBug
|
|
209
|
+
{
|
|
210
|
+
public:
|
|
211
|
+
PartialBufferOverflowBug( const EventStack &eventStack,
|
|
212
|
+
s64_t allocLowerBound, s64_t allocUpperBound,
|
|
213
|
+
s64_t accessLowerBound, s64_t accessUpperBound):
|
|
214
|
+
BufferOverflowBug(GenericBug::PARTIALBUFOVERFLOW, eventStack, allocLowerBound,
|
|
215
|
+
allocUpperBound, accessLowerBound, accessUpperBound) { }
|
|
216
|
+
|
|
217
|
+
/// ClassOf
|
|
218
|
+
static inline bool classof(const GenericBug *bug)
|
|
219
|
+
{
|
|
220
|
+
return bug->getBugType() == GenericBug::PARTIALBUFOVERFLOW;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
class NeverFreeBug : public GenericBug
|
|
225
|
+
{
|
|
226
|
+
public:
|
|
227
|
+
NeverFreeBug(const EventStack &bugEventStack):
|
|
228
|
+
GenericBug(GenericBug::NEVERFREE, bugEventStack) { };
|
|
229
|
+
|
|
230
|
+
cJSON *getBugDescription() const;
|
|
231
|
+
void printBugToTerminal() const;
|
|
232
|
+
|
|
233
|
+
/// ClassOf
|
|
234
|
+
static inline bool classof(const GenericBug *bug)
|
|
235
|
+
{
|
|
236
|
+
return bug->getBugType() == GenericBug::NEVERFREE;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
class PartialLeakBug : public GenericBug
|
|
241
|
+
{
|
|
242
|
+
public:
|
|
243
|
+
PartialLeakBug(const EventStack &bugEventStack):
|
|
244
|
+
GenericBug(GenericBug::PARTIALLEAK, bugEventStack) { }
|
|
245
|
+
|
|
246
|
+
cJSON *getBugDescription() const;
|
|
247
|
+
void printBugToTerminal() const;
|
|
248
|
+
|
|
249
|
+
/// ClassOf
|
|
250
|
+
static inline bool classof(const GenericBug *bug)
|
|
251
|
+
{
|
|
252
|
+
return bug->getBugType() == GenericBug::PARTIALLEAK;
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
class DoubleFreeBug : public GenericBug
|
|
257
|
+
{
|
|
258
|
+
public:
|
|
259
|
+
DoubleFreeBug(const EventStack &bugEventStack):
|
|
260
|
+
GenericBug(GenericBug::PARTIALLEAK, bugEventStack) { }
|
|
261
|
+
|
|
262
|
+
cJSON *getBugDescription() const;
|
|
263
|
+
void printBugToTerminal() const;
|
|
264
|
+
|
|
265
|
+
/// ClassOf
|
|
266
|
+
static inline bool classof(const GenericBug *bug)
|
|
267
|
+
{
|
|
268
|
+
return bug->getBugType() == GenericBug::DOUBLEFREE;
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
class FileNeverCloseBug : public GenericBug
|
|
273
|
+
{
|
|
274
|
+
public:
|
|
275
|
+
FileNeverCloseBug(const EventStack &bugEventStack):
|
|
276
|
+
GenericBug(GenericBug::NEVERFREE, bugEventStack) { };
|
|
277
|
+
|
|
278
|
+
cJSON *getBugDescription() const;
|
|
279
|
+
void printBugToTerminal() const;
|
|
280
|
+
|
|
281
|
+
/// ClassOf
|
|
282
|
+
static inline bool classof(const GenericBug *bug)
|
|
283
|
+
{
|
|
284
|
+
return bug->getBugType() == GenericBug::FILENEVERCLOSE;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
class FilePartialCloseBug : public GenericBug
|
|
289
|
+
{
|
|
290
|
+
public:
|
|
291
|
+
FilePartialCloseBug(const EventStack &bugEventStack):
|
|
292
|
+
GenericBug(GenericBug::PARTIALLEAK, bugEventStack) { }
|
|
293
|
+
|
|
294
|
+
cJSON *getBugDescription() const;
|
|
295
|
+
void printBugToTerminal() const;
|
|
296
|
+
|
|
297
|
+
/// ClassOf
|
|
298
|
+
static inline bool classof(const GenericBug *bug)
|
|
299
|
+
{
|
|
300
|
+
return bug->getBugType() == GenericBug::FILEPARTIALCLOSE;
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
class SVFBugReport
|
|
305
|
+
{
|
|
306
|
+
public:
|
|
307
|
+
SVFBugReport() = default;
|
|
308
|
+
~SVFBugReport();
|
|
309
|
+
typedef SVF::Set<const GenericBug *> BugSet;
|
|
310
|
+
typedef SVF::Set<const GenericEvent *> EventSet;
|
|
311
|
+
|
|
312
|
+
protected:
|
|
313
|
+
BugSet bugSet; // maintain bugs
|
|
314
|
+
EventSet eventSet;// maintain added events
|
|
315
|
+
|
|
316
|
+
public:
|
|
317
|
+
/*
|
|
318
|
+
* function: pass bug type (i.e., GenericBug::NEVERFREE) and eventStack as parameter,
|
|
319
|
+
* it will add the bug into bugQueue.
|
|
320
|
+
* usage: addSaberBug(GenericBug::NEVERFREE, eventStack)
|
|
321
|
+
*/
|
|
322
|
+
void addSaberBug(GenericBug::BugType bugType, const GenericBug::EventStack &eventStack)
|
|
323
|
+
{
|
|
324
|
+
/// resign added events
|
|
325
|
+
for(auto eventPtr : eventStack)
|
|
326
|
+
{
|
|
327
|
+
eventSet.insert(eventPtr);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/// create and add the bug
|
|
331
|
+
GenericBug *newBug = nullptr;
|
|
332
|
+
switch(bugType)
|
|
333
|
+
{
|
|
334
|
+
case GenericBug::NEVERFREE:
|
|
335
|
+
{
|
|
336
|
+
newBug = new NeverFreeBug(eventStack);
|
|
337
|
+
bugSet.insert(newBug);
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
case GenericBug::PARTIALLEAK:
|
|
341
|
+
{
|
|
342
|
+
newBug = new PartialLeakBug(eventStack);
|
|
343
|
+
bugSet.insert(newBug);
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
case GenericBug::DOUBLEFREE:
|
|
347
|
+
{
|
|
348
|
+
newBug = new DoubleFreeBug(eventStack);
|
|
349
|
+
bugSet.insert(newBug);
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
case GenericBug::FILENEVERCLOSE:
|
|
353
|
+
{
|
|
354
|
+
newBug = new FileNeverCloseBug(eventStack);
|
|
355
|
+
bugSet.insert(newBug);
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
case GenericBug::FILEPARTIALCLOSE:
|
|
359
|
+
{
|
|
360
|
+
newBug = new FilePartialCloseBug(eventStack);
|
|
361
|
+
bugSet.insert(newBug);
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
default:
|
|
365
|
+
{
|
|
366
|
+
assert(false && "saber does NOT have this bug type!");
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// when add a bug, also print it to terminal
|
|
372
|
+
newBug->printBugToTerminal();
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/*
|
|
376
|
+
* function: pass bug type (i.e., GenericBug::FULLBUFOVERFLOW) and eventStack as parameter,
|
|
377
|
+
* it will add the bug into bugQueue.
|
|
378
|
+
* usage: addAbsExecBug(GenericBug::FULLBUFOVERFLOW, eventStack, 0, 10, 11, 11)
|
|
379
|
+
*/
|
|
380
|
+
void addAbsExecBug(GenericBug::BugType bugType, const GenericBug::EventStack &eventStack,
|
|
381
|
+
s64_t allocLowerBound, s64_t allocUpperBound, s64_t accessLowerBound, s64_t accessUpperBound)
|
|
382
|
+
{
|
|
383
|
+
/// resign added events
|
|
384
|
+
for(auto eventPtr : eventStack)
|
|
385
|
+
{
|
|
386
|
+
eventSet.insert(eventPtr);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/// add bugs
|
|
390
|
+
GenericBug *newBug = nullptr;
|
|
391
|
+
switch(bugType)
|
|
392
|
+
{
|
|
393
|
+
case GenericBug::FULLBUFOVERFLOW:
|
|
394
|
+
{
|
|
395
|
+
newBug = new FullBufferOverflowBug(eventStack, allocLowerBound, allocUpperBound, accessLowerBound, accessUpperBound);
|
|
396
|
+
bugSet.insert(newBug);
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
case GenericBug::PARTIALBUFOVERFLOW:
|
|
400
|
+
{
|
|
401
|
+
newBug = new PartialBufferOverflowBug(eventStack, allocLowerBound, allocUpperBound, accessLowerBound, accessUpperBound);
|
|
402
|
+
bugSet.insert(newBug);
|
|
403
|
+
break;
|
|
404
|
+
}
|
|
405
|
+
default:
|
|
406
|
+
{
|
|
407
|
+
assert(false && "Abstract Execution does NOT hava his bug type!");
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// when add a bug, also print it to terminal
|
|
413
|
+
newBug->printBugToTerminal();
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/*
|
|
417
|
+
* function: pass file path, open the file and dump bug report as JSON format
|
|
418
|
+
* usage: dumpToFile("/path/to/file")
|
|
419
|
+
*/
|
|
420
|
+
void dumpToJsonFile(const std::string& filePath);
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
#endif
|
|
@@ -600,7 +600,7 @@ void SVFIR2ItvExeState::translateLoad(const LoadStmt *load)
|
|
|
600
600
|
if (inLocToIValTable(objId))
|
|
601
601
|
_es[lhs] = IntervalValue::bottom();
|
|
602
602
|
else if (inLocToAddrsTable(objId))
|
|
603
|
-
getVAddrs(lhs).setBottom();
|
|
603
|
+
_es.getVAddrs(lhs).setBottom();
|
|
604
604
|
break;
|
|
605
605
|
}
|
|
606
606
|
for (const auto &addr: addrs)
|
|
@@ -621,11 +621,11 @@ void SVFIR2ItvExeState::translateLoad(const LoadStmt *load)
|
|
|
621
621
|
{
|
|
622
622
|
if (!inVarToAddrsTable(lhs))
|
|
623
623
|
{
|
|
624
|
-
|
|
624
|
+
_es.getVAddrs(lhs) = _es.loadVAddrs(addr);
|
|
625
625
|
}
|
|
626
626
|
else
|
|
627
627
|
{
|
|
628
|
-
getVAddrs(lhs).join_with(_es.loadVAddrs(addr));
|
|
628
|
+
_es.getVAddrs(lhs).join_with(_es.loadVAddrs(addr));
|
|
629
629
|
}
|
|
630
630
|
}
|
|
631
631
|
}
|
|
@@ -678,7 +678,7 @@ void SVFIR2ItvExeState::translateCopy(const CopyStmt *copy)
|
|
|
678
678
|
else if (inVarToAddrsTable(rhs))
|
|
679
679
|
{
|
|
680
680
|
assert(!getVAddrs(rhs).empty());
|
|
681
|
-
|
|
681
|
+
_es.getVAddrs(lhs) = getVAddrs(rhs);
|
|
682
682
|
}
|
|
683
683
|
}
|
|
684
684
|
}
|
|
@@ -738,7 +738,7 @@ void SVFIR2ItvExeState::translateSelect(const SelectStmt *select)
|
|
|
738
738
|
{
|
|
739
739
|
assert(!getVAddrs(fval).empty());
|
|
740
740
|
assert(!getVAddrs(tval).empty());
|
|
741
|
-
|
|
741
|
+
_es.getVAddrs(res) = _es[cond].is_zero() ? getVAddrs(fval) : getVAddrs(tval);
|
|
742
742
|
}
|
|
743
743
|
}
|
|
744
744
|
}
|
|
@@ -767,11 +767,11 @@ void SVFIR2ItvExeState::translatePhi(const PhiStmt *phi)
|
|
|
767
767
|
const VAddrs &cur = getVAddrs(curId);
|
|
768
768
|
if (!inVarToAddrsTable(res))
|
|
769
769
|
{
|
|
770
|
-
|
|
770
|
+
_es.getVAddrs(res) = cur;
|
|
771
771
|
}
|
|
772
772
|
else
|
|
773
773
|
{
|
|
774
|
-
getVAddrs(res).join_with(cur);
|
|
774
|
+
_es.getVAddrs(res).join_with(cur);
|
|
775
775
|
}
|
|
776
776
|
}
|
|
777
777
|
}
|
|
@@ -789,7 +789,7 @@ void SVFIR2ItvExeState::translateCall(const CallPE *callPE)
|
|
|
789
789
|
else if (inVarToAddrsTable(rhs))
|
|
790
790
|
{
|
|
791
791
|
assert(!getVAddrs(rhs).empty());
|
|
792
|
-
|
|
792
|
+
_es.getVAddrs(lhs) = getVAddrs(rhs);
|
|
793
793
|
}
|
|
794
794
|
}
|
|
795
795
|
|
|
@@ -804,6 +804,6 @@ void SVFIR2ItvExeState::translateRet(const RetPE *retPE)
|
|
|
804
804
|
else if (inVarToAddrsTable(rhs))
|
|
805
805
|
{
|
|
806
806
|
assert(!getVAddrs(rhs).empty());
|
|
807
|
-
|
|
807
|
+
_es.getVAddrs(lhs) = getVAddrs(rhs);
|
|
808
808
|
}
|
|
809
809
|
}
|
|
@@ -39,11 +39,11 @@ void DoubleFreeChecker::reportBug(ProgSlice* slice)
|
|
|
39
39
|
|
|
40
40
|
if(slice->isSatisfiableForPairs() == false)
|
|
41
41
|
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
SourceInstEvent*sourceInstEvent = new SourceInstEvent(getSrcCSID(slice->getSource())->getCallSite());
|
|
43
|
+
GenericBug::EventStack eventStack;
|
|
44
|
+
slice->evalFinalCond2Event(eventStack);
|
|
45
|
+
eventStack.push_back(sourceInstEvent);
|
|
46
|
+
report.addSaberBug(GenericBug::DOUBLEFREE, eventStack);
|
|
47
47
|
}
|
|
48
48
|
if(Options::ValidateTests())
|
|
49
49
|
testsValidation(slice);
|
|
@@ -33,31 +33,22 @@ using namespace SVF;
|
|
|
33
33
|
using namespace SVFUtil;
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
void FileChecker::reportNeverClose(const SVFGNode* src)
|
|
37
|
-
{
|
|
38
|
-
const CallICFGNode* cs = getSrcCSID(src);
|
|
39
|
-
SVFUtil::errs() << bugMsg1("\t FileNeverClose :") << " file open location at : ("
|
|
40
|
-
<< cs->getCallSite()->getSourceLoc() << ")\n";
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
void FileChecker::reportPartialClose(const SVFGNode* src)
|
|
44
|
-
{
|
|
45
|
-
const CallICFGNode* cs = getSrcCSID(src);
|
|
46
|
-
SVFUtil::errs() << bugMsg2("\t PartialFileClose :") << " file open location at : ("
|
|
47
|
-
<< cs->getCallSite()->getSourceLoc() << ")\n";
|
|
48
|
-
}
|
|
49
|
-
|
|
50
36
|
void FileChecker::reportBug(ProgSlice* slice)
|
|
51
37
|
{
|
|
52
38
|
|
|
53
39
|
if(isAllPathReachable() == false && isSomePathReachable() == false)
|
|
54
40
|
{
|
|
55
|
-
|
|
41
|
+
// full leakage
|
|
42
|
+
SourceInstEvent*sourceInstEvent = new SourceInstEvent(getSrcCSID(slice->getSource())->getCallSite());
|
|
43
|
+
GenericBug::EventStack eventStack = {sourceInstEvent};
|
|
44
|
+
report.addSaberBug(GenericBug::FILENEVERCLOSE, eventStack);
|
|
56
45
|
}
|
|
57
46
|
else if (isAllPathReachable() == false && isSomePathReachable() == true)
|
|
58
47
|
{
|
|
59
|
-
|
|
60
|
-
|
|
48
|
+
SourceInstEvent*sourceInstEvent = new SourceInstEvent(getSrcCSID(slice->getSource())->getCallSite());
|
|
49
|
+
GenericBug::EventStack eventStack;
|
|
50
|
+
slice->evalFinalCond2Event(eventStack);
|
|
51
|
+
eventStack.push_back(sourceInstEvent);
|
|
52
|
+
report.addSaberBug(GenericBug::FILEPARTIALCLOSE, eventStack);
|
|
61
53
|
}
|
|
62
|
-
|
|
63
54
|
}
|
|
@@ -146,33 +146,24 @@ void LeakChecker::initSnks()
|
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
void LeakChecker::reportNeverFree(const SVFGNode* src)
|
|
151
|
-
{
|
|
152
|
-
const CallICFGNode* cs = getSrcCSID(src);
|
|
153
|
-
SVFUtil::errs() << bugMsg1("\t NeverFree :") << " memory allocation at : ("
|
|
154
|
-
<< cs->getCallSite()->getSourceLoc() << ")\n";
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
void LeakChecker::reportPartialLeak(const SVFGNode* src)
|
|
158
|
-
{
|
|
159
|
-
|
|
160
|
-
const CallICFGNode* cs = getSrcCSID(src);
|
|
161
|
-
SVFUtil::errs() << bugMsg2("\t PartialLeak :") << " memory allocation at : ("
|
|
162
|
-
<< cs->getCallSite()->getSourceLoc() << ")\n";
|
|
163
|
-
}
|
|
164
|
-
|
|
165
149
|
void LeakChecker::reportBug(ProgSlice* slice)
|
|
166
150
|
{
|
|
167
151
|
|
|
168
152
|
if(isAllPathReachable() == false && isSomePathReachable() == false)
|
|
169
153
|
{
|
|
170
|
-
|
|
154
|
+
// full leakage
|
|
155
|
+
SourceInstEvent*sourceInstEvent = new SourceInstEvent(getSrcCSID(slice->getSource())->getCallSite());
|
|
156
|
+
GenericBug::EventStack eventStack = {sourceInstEvent};
|
|
157
|
+
report.addSaberBug(GenericBug::NEVERFREE, eventStack);
|
|
171
158
|
}
|
|
172
159
|
else if (isAllPathReachable() == false && isSomePathReachable() == true)
|
|
173
160
|
{
|
|
174
|
-
|
|
175
|
-
|
|
161
|
+
// partial leakage
|
|
162
|
+
SourceInstEvent*sourceInstEvent = new SourceInstEvent(getSrcCSID(slice->getSource())->getCallSite());
|
|
163
|
+
GenericBug::EventStack eventStack;
|
|
164
|
+
slice->evalFinalCond2Event(eventStack);
|
|
165
|
+
eventStack.push_back(sourceInstEvent);
|
|
166
|
+
report.addSaberBug(GenericBug::PARTIALLEAK, eventStack);
|
|
176
167
|
}
|
|
177
168
|
|
|
178
169
|
if(Options::ValidateTests())
|
|
@@ -146,6 +146,19 @@ const CallICFGNode* ProgSlice::getRetSite(const SVFGEdge* edge) const
|
|
|
146
146
|
return getSVFG()->getCallSite(SVFUtil::cast<RetIndSVFGEdge>(edge)->getCallSiteId());
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
void ProgSlice::evalFinalCond2Event(GenericBug::EventStack &eventStack) const
|
|
150
|
+
{
|
|
151
|
+
NodeBS elems = pathAllocator->exactCondElem(finalCond);
|
|
152
|
+
Set<std::string> locations;
|
|
153
|
+
for(NodeBS::iterator it = elems.begin(), eit = elems.end(); it!=eit; ++it)
|
|
154
|
+
{
|
|
155
|
+
const SVFInstruction* tinst = pathAllocator->getCondInst(*it);
|
|
156
|
+
if(pathAllocator->isNegCond(*it))
|
|
157
|
+
eventStack.push_back(new BranchEvent(tinst, false));
|
|
158
|
+
else
|
|
159
|
+
eventStack.push_back(new BranchEvent(tinst, true));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
149
162
|
|
|
150
163
|
/*!
|
|
151
164
|
* Evaluate Atoms of a condition
|
|
@@ -160,8 +173,9 @@ std::string ProgSlice::evalFinalCond() const
|
|
|
160
173
|
{
|
|
161
174
|
std::string str;
|
|
162
175
|
std::stringstream rawstr(str);
|
|
163
|
-
NodeBS elems = pathAllocator->exactCondElem(finalCond);
|
|
164
176
|
Set<std::string> locations;
|
|
177
|
+
NodeBS elems = pathAllocator->exactCondElem(finalCond);
|
|
178
|
+
|
|
165
179
|
for(NodeBS::iterator it = elems.begin(), eit = elems.end(); it!=eit; ++it)
|
|
166
180
|
{
|
|
167
181
|
const SVFInstruction* tinst = pathAllocator->getCondInst(*it);
|
|
@@ -170,6 +184,7 @@ std::string ProgSlice::evalFinalCond() const
|
|
|
170
184
|
else
|
|
171
185
|
locations.insert(tinst->getSourceLoc()+"|True");
|
|
172
186
|
}
|
|
187
|
+
|
|
173
188
|
/// print leak path after eliminating duplicated element
|
|
174
189
|
for(Set<std::string>::iterator iter = locations.begin(), eiter = locations.end();
|
|
175
190
|
iter!=eiter; ++iter)
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
//===- SVFBugReport.cpp -- Base class for statistics---------------------------------//
|
|
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 JoelYang on 2023/4/19.
|
|
26
|
+
//
|
|
27
|
+
|
|
28
|
+
#include "Util/SVFBugReport.h"
|
|
29
|
+
#include <cassert>
|
|
30
|
+
#include "Util/cJSON.h"
|
|
31
|
+
#include "Util/SVFUtil.h"
|
|
32
|
+
#include <sstream>
|
|
33
|
+
#include <fstream>
|
|
34
|
+
|
|
35
|
+
using namespace std;
|
|
36
|
+
using namespace SVF;
|
|
37
|
+
|
|
38
|
+
const std::string GenericBug::getLoc() const
|
|
39
|
+
{
|
|
40
|
+
const GenericEvent *sourceInstEvent = bugEventStack.at(bugEventStack.size() -1);
|
|
41
|
+
assert(SourceInstEvent::classof(sourceInstEvent) && "bugEventStack top should be a SourceInst event");
|
|
42
|
+
return sourceInstEvent->getEventLoc();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const std::string GenericBug::getFuncName() const
|
|
46
|
+
{
|
|
47
|
+
const GenericEvent *sourceInstEvent = bugEventStack.at(bugEventStack.size() -1);
|
|
48
|
+
assert(SourceInstEvent::classof(sourceInstEvent) && "bugEventStack top should be a SourceInst event");
|
|
49
|
+
return sourceInstEvent->getFuncName();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
cJSON *BufferOverflowBug::getBugDescription() const
|
|
53
|
+
{
|
|
54
|
+
cJSON *bugDescription = cJSON_CreateObject();
|
|
55
|
+
cJSON *allocLB = cJSON_CreateNumber(allocLowerBound);
|
|
56
|
+
cJSON *allocUB = cJSON_CreateNumber(allocUpperBound);
|
|
57
|
+
cJSON *accessLB = cJSON_CreateNumber(accessLowerBound);
|
|
58
|
+
cJSON *accessUB = cJSON_CreateNumber(accessUpperBound);
|
|
59
|
+
|
|
60
|
+
cJSON_AddItemToObject(bugDescription, "AllocLowerBound", allocLB);
|
|
61
|
+
cJSON_AddItemToObject(bugDescription, "AllocUpperBound", allocUB);
|
|
62
|
+
cJSON_AddItemToObject(bugDescription, "AccessLowerBound", accessLB);
|
|
63
|
+
cJSON_AddItemToObject(bugDescription, "AccessUpperBound", accessUB);
|
|
64
|
+
|
|
65
|
+
return bugDescription;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void BufferOverflowBug::printBugToTerminal() const
|
|
69
|
+
{
|
|
70
|
+
stringstream bugInfo;
|
|
71
|
+
if(FullBufferOverflowBug::classof(this))
|
|
72
|
+
{
|
|
73
|
+
SVFUtil::errs() << SVFUtil::bugMsg1("\t Full Overflow :") << " accessing at : ("
|
|
74
|
+
<< GenericBug::getLoc() << ")\n";
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
else
|
|
78
|
+
{
|
|
79
|
+
SVFUtil::errs() << SVFUtil::bugMsg1("\t Partial Overflow :") << " accessing at : ("
|
|
80
|
+
<< GenericBug::getLoc() << ")\n";
|
|
81
|
+
}
|
|
82
|
+
bugInfo << "\t\t allocate size : [" << allocLowerBound << ", " << allocUpperBound << "], ";
|
|
83
|
+
bugInfo << "access size : [" << accessLowerBound << ", " << accessUpperBound << "]\n";
|
|
84
|
+
SVFUtil::errs() << "\t\t Info : \n" << bugInfo.str();
|
|
85
|
+
SVFUtil::errs() << "\t\t Events : \n";
|
|
86
|
+
|
|
87
|
+
for(auto eventPtr : bugEventStack)
|
|
88
|
+
{
|
|
89
|
+
switch(eventPtr->getEventType())
|
|
90
|
+
{
|
|
91
|
+
case GenericEvent::CallSite:
|
|
92
|
+
{
|
|
93
|
+
SVFUtil::errs() << "\t\t callsite at : ( " << eventPtr->getEventLoc() << " )\n";
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
default: // TODO: implement more events when needed
|
|
97
|
+
{
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
cJSON * NeverFreeBug::getBugDescription() const
|
|
106
|
+
{
|
|
107
|
+
cJSON *bugDescription = cJSON_CreateObject();
|
|
108
|
+
return bugDescription;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
void NeverFreeBug::printBugToTerminal() const
|
|
112
|
+
{
|
|
113
|
+
SVFUtil::errs() << SVFUtil::bugMsg1("\t NeverFree :") << " memory allocation at : ("
|
|
114
|
+
<< GenericBug::getLoc() << ")\n";
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
cJSON * PartialLeakBug::getBugDescription() const
|
|
118
|
+
{
|
|
119
|
+
cJSON *bugDescription = cJSON_CreateObject();
|
|
120
|
+
cJSON *pathInfo = cJSON_CreateArray();
|
|
121
|
+
auto lastBranchEventIt = bugEventStack.end() - 1;
|
|
122
|
+
for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
|
|
123
|
+
{
|
|
124
|
+
cJSON *newBranch = cJSON_CreateObject();
|
|
125
|
+
cJSON *branchLoc = cJSON_Parse((*eventIt)->getEventLoc().c_str());
|
|
126
|
+
if(branchLoc == nullptr) branchLoc = cJSON_CreateObject();
|
|
127
|
+
cJSON *branchCondition = cJSON_CreateString((*eventIt)->getEventDescription().c_str());
|
|
128
|
+
|
|
129
|
+
cJSON_AddItemToObject(newBranch, "BranchLoc", branchLoc);
|
|
130
|
+
cJSON_AddItemToObject(newBranch, "BranchCond", branchCondition);
|
|
131
|
+
|
|
132
|
+
cJSON_AddItemToArray(pathInfo, newBranch);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
cJSON_AddItemToObject(bugDescription, "ConditionalFreePath", pathInfo);
|
|
136
|
+
|
|
137
|
+
return bugDescription;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
void PartialLeakBug::printBugToTerminal() const
|
|
141
|
+
{
|
|
142
|
+
SVFUtil::errs() << SVFUtil::bugMsg2("\t PartialLeak :") << " memory allocation at : ("
|
|
143
|
+
<< GenericBug::getLoc() << ")\n";
|
|
144
|
+
|
|
145
|
+
SVFUtil::errs() << "\t\t conditional free path: \n";
|
|
146
|
+
auto lastBranchEventIt = bugEventStack.end() - 1;
|
|
147
|
+
for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
|
|
148
|
+
{
|
|
149
|
+
SVFUtil::errs() << "\t\t --> (" << (*eventIt)->getEventLoc() << "|" << (*eventIt)->getEventDescription() << ") \n";
|
|
150
|
+
}
|
|
151
|
+
SVFUtil::errs() << "\n";
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
cJSON * DoubleFreeBug::getBugDescription() const
|
|
155
|
+
{
|
|
156
|
+
cJSON *bugDescription = cJSON_CreateObject();
|
|
157
|
+
|
|
158
|
+
cJSON *pathInfo = cJSON_CreateArray();
|
|
159
|
+
auto lastBranchEventIt = bugEventStack.end() - 1;
|
|
160
|
+
for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
|
|
161
|
+
{
|
|
162
|
+
cJSON *newBranch = cJSON_CreateObject();
|
|
163
|
+
cJSON *branchLoc = cJSON_Parse((*eventIt)->getEventLoc().c_str());
|
|
164
|
+
if(branchLoc == nullptr) branchLoc = cJSON_CreateObject();
|
|
165
|
+
cJSON *branchCondition = cJSON_CreateString((*eventIt)->getEventDescription().c_str());
|
|
166
|
+
|
|
167
|
+
cJSON_AddItemToObject(newBranch, "BranchLoc", branchLoc);
|
|
168
|
+
cJSON_AddItemToObject(newBranch, "BranchCond", branchCondition);
|
|
169
|
+
|
|
170
|
+
cJSON_AddItemToArray(pathInfo, newBranch);
|
|
171
|
+
}
|
|
172
|
+
cJSON_AddItemToObject(bugDescription, "DoubleFreePath", pathInfo);
|
|
173
|
+
|
|
174
|
+
return bugDescription;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
void DoubleFreeBug::printBugToTerminal() const
|
|
178
|
+
{
|
|
179
|
+
SVFUtil::errs() << SVFUtil::bugMsg2("\t Double Free :") << " memory allocation at : ("
|
|
180
|
+
<< GenericBug::getLoc() << ")\n";
|
|
181
|
+
|
|
182
|
+
SVFUtil::errs() << "\t\t double free path: \n";
|
|
183
|
+
auto lastBranchEventIt = bugEventStack.end() - 1;
|
|
184
|
+
for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
|
|
185
|
+
{
|
|
186
|
+
SVFUtil::errs() << "\t\t --> (" << (*eventIt)->getEventLoc() << "|" << (*eventIt)->getEventDescription() << ") \n";
|
|
187
|
+
}
|
|
188
|
+
SVFUtil::errs() << "\n";
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
cJSON * FileNeverCloseBug::getBugDescription() const
|
|
192
|
+
{
|
|
193
|
+
cJSON *bugDescription = cJSON_CreateObject();
|
|
194
|
+
return bugDescription;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
void FileNeverCloseBug::printBugToTerminal() const
|
|
198
|
+
{
|
|
199
|
+
SVFUtil::errs() << SVFUtil::bugMsg1("\t FileNeverClose :") << " file open location at : ("
|
|
200
|
+
<< GenericBug::getLoc() << ")\n";
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
cJSON * FilePartialCloseBug::getBugDescription() const
|
|
204
|
+
{
|
|
205
|
+
cJSON *bugDescription = cJSON_CreateObject();
|
|
206
|
+
|
|
207
|
+
cJSON *pathInfo = cJSON_CreateArray();
|
|
208
|
+
|
|
209
|
+
auto lastBranchEventIt = bugEventStack.end() - 1;
|
|
210
|
+
for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
|
|
211
|
+
{
|
|
212
|
+
cJSON *newBranch = cJSON_CreateObject();
|
|
213
|
+
cJSON *branchLoc = cJSON_Parse((*eventIt)->getEventLoc().c_str());
|
|
214
|
+
if(branchLoc == nullptr) branchLoc = cJSON_CreateObject();
|
|
215
|
+
cJSON *branchCondition = cJSON_CreateString((*eventIt)->getEventDescription().c_str());
|
|
216
|
+
|
|
217
|
+
cJSON_AddItemToObject(newBranch, "BranchLoc", branchLoc);
|
|
218
|
+
cJSON_AddItemToObject(newBranch, "BranchCond", branchCondition);
|
|
219
|
+
|
|
220
|
+
cJSON_AddItemToArray(pathInfo, newBranch);
|
|
221
|
+
}
|
|
222
|
+
cJSON_AddItemToObject(bugDescription, "ConditionalFileClosePath", pathInfo);
|
|
223
|
+
|
|
224
|
+
return bugDescription;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
void FilePartialCloseBug::printBugToTerminal() const
|
|
228
|
+
{
|
|
229
|
+
SVFUtil::errs() << SVFUtil::bugMsg2("\t PartialFileClose :") << " file open location at : ("
|
|
230
|
+
<< GenericBug::getLoc() << ")\n";
|
|
231
|
+
|
|
232
|
+
SVFUtil::errs() << "\t\t conditional file close path: \n";
|
|
233
|
+
auto lastBranchEventIt = bugEventStack.end() - 1;
|
|
234
|
+
for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
|
|
235
|
+
{
|
|
236
|
+
SVFUtil::errs() << "\t\t --> (" << (*eventIt)->getEventLoc() << "|" << (*eventIt)->getEventDescription() << ") \n";
|
|
237
|
+
}
|
|
238
|
+
SVFUtil::errs() << "\n";
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const std::string CallSiteEvent::getFuncName() const
|
|
242
|
+
{
|
|
243
|
+
return callSite->getCallSite()->getFunction()->getName();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const std::string CallSiteEvent::getEventLoc() const
|
|
247
|
+
{
|
|
248
|
+
return callSite->getCallSite()->getSourceLoc();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const std::string CallSiteEvent::getEventDescription() const
|
|
252
|
+
{
|
|
253
|
+
std::string description("calls ");
|
|
254
|
+
const SVFFunction *callee = SVFUtil::getCallee(callSite->getCallSite());
|
|
255
|
+
if(callee == nullptr)
|
|
256
|
+
{
|
|
257
|
+
description += "<unknown>";
|
|
258
|
+
}
|
|
259
|
+
else
|
|
260
|
+
{
|
|
261
|
+
description += callee->getName();
|
|
262
|
+
}
|
|
263
|
+
return description;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const std::string BranchEvent::getFuncName() const
|
|
267
|
+
{
|
|
268
|
+
return branchInst->getFunction()->getName();
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const std::string BranchEvent::getEventLoc() const
|
|
272
|
+
{
|
|
273
|
+
return branchInst->getSourceLoc();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const std::string BranchEvent::getEventDescription() const
|
|
277
|
+
{
|
|
278
|
+
if (branchSuccessFlg)
|
|
279
|
+
{
|
|
280
|
+
return "True";
|
|
281
|
+
}
|
|
282
|
+
else
|
|
283
|
+
{
|
|
284
|
+
return "False";
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const std::string SourceInstEvent::getFuncName() const
|
|
289
|
+
{
|
|
290
|
+
return sourceSVFInst->getFunction()->getName();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const std::string SourceInstEvent::getEventLoc() const
|
|
294
|
+
{
|
|
295
|
+
return sourceSVFInst->getSourceLoc();
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const std::string SourceInstEvent::getEventDescription() const
|
|
299
|
+
{
|
|
300
|
+
return "None";
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
SVFBugReport::~SVFBugReport()
|
|
304
|
+
{
|
|
305
|
+
for(auto bugIt: bugSet)
|
|
306
|
+
{
|
|
307
|
+
delete bugIt;
|
|
308
|
+
}
|
|
309
|
+
for(auto eventPtr:eventSet)
|
|
310
|
+
{
|
|
311
|
+
delete eventPtr;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
void SVFBugReport::dumpToJsonFile(const std::string& filePath)
|
|
316
|
+
{
|
|
317
|
+
std::map<GenericEvent::EventType, std::string> eventType2Str =
|
|
318
|
+
{
|
|
319
|
+
{GenericEvent::CallSite, "call site"},
|
|
320
|
+
{GenericEvent::Caller, "caller"},
|
|
321
|
+
{GenericEvent::Loop, "loop"},
|
|
322
|
+
{GenericEvent::Branch, "branch"}
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
std::map<GenericBug::BugType, std::string> bugType2Str =
|
|
326
|
+
{
|
|
327
|
+
{GenericBug::FULLBUFOVERFLOW, "Full Buffer Overflow"},
|
|
328
|
+
{GenericBug::PARTIALBUFOVERFLOW, "Partial Buffer Overflow"},
|
|
329
|
+
{GenericBug::NEVERFREE, "Never Free"},
|
|
330
|
+
{GenericBug::PARTIALLEAK, "Partial Leak"},
|
|
331
|
+
{GenericBug::FILENEVERCLOSE, "File Never Close"},
|
|
332
|
+
{GenericBug::FILEPARTIALCLOSE, "File Partial Close"},
|
|
333
|
+
{GenericBug::DOUBLEFREE, "Double Free"}
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
ofstream jsonFile(filePath, ios::out);
|
|
337
|
+
|
|
338
|
+
jsonFile << "{";
|
|
339
|
+
|
|
340
|
+
size_t commaCounter = bugSet.size() - 1; // comma num needed
|
|
341
|
+
for(auto bugPtr : bugSet)
|
|
342
|
+
{
|
|
343
|
+
cJSON *singleBug = cJSON_CreateObject();
|
|
344
|
+
|
|
345
|
+
/// add bug information to json
|
|
346
|
+
cJSON *bugType = cJSON_CreateString(bugType2Str[bugPtr->getBugType()].c_str());
|
|
347
|
+
cJSON_AddItemToObject(singleBug, "DefectType", bugType);
|
|
348
|
+
|
|
349
|
+
cJSON *bugLoc = cJSON_Parse(bugPtr->getLoc().c_str());
|
|
350
|
+
if(bugLoc == nullptr)
|
|
351
|
+
{
|
|
352
|
+
bugLoc = cJSON_CreateObject();
|
|
353
|
+
}
|
|
354
|
+
cJSON_AddItemToObject(singleBug, "Location", bugLoc);
|
|
355
|
+
|
|
356
|
+
cJSON *bugFunction = cJSON_CreateString(bugPtr->getFuncName().c_str());
|
|
357
|
+
cJSON_AddItemToObject(singleBug, "Function", bugFunction);
|
|
358
|
+
|
|
359
|
+
cJSON_AddItemToObject(singleBug, "Description", bugPtr->getBugDescription());
|
|
360
|
+
|
|
361
|
+
/// add event information to json
|
|
362
|
+
cJSON *eventList = cJSON_CreateArray();
|
|
363
|
+
const GenericBug::EventStack bugEventStack = bugPtr->getEventStack();
|
|
364
|
+
if(BufferOverflowBug::classof(bugPtr)) // add only when bug is context sensitive
|
|
365
|
+
{
|
|
366
|
+
for(auto eventPtr : bugEventStack)
|
|
367
|
+
{
|
|
368
|
+
if (SourceInstEvent::classof(eventPtr))
|
|
369
|
+
{
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
cJSON *singleEvent = cJSON_CreateObject();
|
|
374
|
+
//event type
|
|
375
|
+
cJSON *eventType = cJSON_CreateString(eventType2Str[eventPtr->getEventType()].c_str());
|
|
376
|
+
cJSON_AddItemToObject(singleEvent, "EventType", eventType);
|
|
377
|
+
//function name
|
|
378
|
+
cJSON *eventFunc = cJSON_CreateString(eventPtr->getFuncName().c_str());
|
|
379
|
+
cJSON_AddItemToObject(singleEvent, "Function", eventFunc);
|
|
380
|
+
//event loc
|
|
381
|
+
cJSON *eventLoc = cJSON_Parse(eventPtr->getEventLoc().c_str());
|
|
382
|
+
if(eventLoc == nullptr)
|
|
383
|
+
{
|
|
384
|
+
eventLoc = cJSON_CreateObject();
|
|
385
|
+
}
|
|
386
|
+
cJSON_AddItemToObject(singleEvent, "Location", eventLoc);
|
|
387
|
+
//event description
|
|
388
|
+
cJSON *eventDescription = cJSON_CreateString(eventPtr->getEventDescription().c_str());
|
|
389
|
+
cJSON_AddItemToObject(singleEvent, "Description", eventDescription);
|
|
390
|
+
|
|
391
|
+
cJSON_AddItemToArray(eventList, singleEvent);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
cJSON_AddItemToObject(singleBug, "Events", eventList);
|
|
395
|
+
|
|
396
|
+
/// dump single bug to json str and write to file
|
|
397
|
+
char *singleBugStr = cJSON_Print(singleBug);
|
|
398
|
+
jsonFile << singleBugStr;
|
|
399
|
+
if (commaCounter != 0)
|
|
400
|
+
{
|
|
401
|
+
jsonFile << ",\n";
|
|
402
|
+
}
|
|
403
|
+
commaCounter --;
|
|
404
|
+
|
|
405
|
+
/// destroy the cJSON object
|
|
406
|
+
cJSON_Delete(singleBug);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
jsonFile << "}";
|
|
410
|
+
jsonFile.close();
|
|
411
|
+
}
|
|
@@ -486,7 +486,7 @@ const std::string LLVMUtil::getSourceLoc(const Value* val )
|
|
|
486
486
|
if (llvm::DbgDeclareInst *DDI = SVFUtil::dyn_cast<llvm::DbgDeclareInst>(DII))
|
|
487
487
|
{
|
|
488
488
|
llvm::DIVariable *DIVar = SVFUtil::cast<llvm::DIVariable>(DDI->getVariable());
|
|
489
|
-
rawstr << "ln: " << DIVar->getLine() << " fl: " << DIVar->getFilename().str();
|
|
489
|
+
rawstr << "\"ln\": " << DIVar->getLine() << ", \"fl\": \"" << DIVar->getFilename().str() << "\"";
|
|
490
490
|
break;
|
|
491
491
|
}
|
|
492
492
|
}
|
|
@@ -508,7 +508,7 @@ const std::string LLVMUtil::getSourceLoc(const Value* val )
|
|
|
508
508
|
File = inlineLoc->getFilename().str();
|
|
509
509
|
}
|
|
510
510
|
}
|
|
511
|
-
rawstr << "ln: " << Line << "
|
|
511
|
+
rawstr << "\"ln\": " << Line << ", \"cl\": " << Column << ", \"fl\": \"" << File << "\"";
|
|
512
512
|
}
|
|
513
513
|
}
|
|
514
514
|
else if (const Argument* argument = SVFUtil::dyn_cast<Argument>(val))
|
|
@@ -539,7 +539,7 @@ const std::string LLVMUtil::getSourceLoc(const Value* val )
|
|
|
539
539
|
|
|
540
540
|
if(DGV->getName() == gvar->getName())
|
|
541
541
|
{
|
|
542
|
-
rawstr << "ln: " << DGV->getLine() << " fl: " << DGV->getFilename().str();
|
|
542
|
+
rawstr << "\"ln\": " << DGV->getLine() << ", \"fl\": \"" << DGV->getFilename().str() << "\"";
|
|
543
543
|
}
|
|
544
544
|
|
|
545
545
|
}
|
|
@@ -552,7 +552,7 @@ const std::string LLVMUtil::getSourceLoc(const Value* val )
|
|
|
552
552
|
}
|
|
553
553
|
else if (const BasicBlock* bb = SVFUtil::dyn_cast<BasicBlock>(val))
|
|
554
554
|
{
|
|
555
|
-
rawstr << "basic block: " << bb->getName().str() << " " << getSourceLoc(bb->getFirstNonPHI());
|
|
555
|
+
rawstr << "\"basic block\": " << bb->getName().str() << ", \"location\": " << getSourceLoc(bb->getFirstNonPHI());
|
|
556
556
|
}
|
|
557
557
|
else if(LLVMUtil::isConstDataOrAggData(val))
|
|
558
558
|
{
|
|
@@ -584,7 +584,7 @@ const std::string LLVMUtil::getSourceLocOfFunction(const Function* F)
|
|
|
584
584
|
if (llvm::DISubprogram *SP = F->getSubprogram())
|
|
585
585
|
{
|
|
586
586
|
if (SP->describes(F))
|
|
587
|
-
rawstr << "
|
|
587
|
+
rawstr << "\"ln\": " << SP->getLine() << ", \"file\": \"" << SP->getFilename().str() << "\"";
|
|
588
588
|
}
|
|
589
589
|
return rawstr.str();
|
|
590
590
|
}
|