svf-tools 1.0.698 → 1.0.700
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/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 +362 -0
- package/svf/lib/SABER/DoubleFreeChecker.cpp +5 -5
- package/svf/lib/SABER/FileChecker.cpp +11 -18
- package/svf/lib/SABER/LeakChecker.cpp +12 -19
- package/svf/lib/SABER/ProgSlice.cpp +17 -1
- package/svf/lib/SABER/SrcSnkDDA.cpp +0 -1
- package/svf/lib/Util/SVFBugReport.cpp +399 -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.700",
|
|
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": {
|
|
@@ -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,362 @@
|
|
|
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
|
+
#define BRANCHFLAGMASK 0x00000010
|
|
41
|
+
#define EVENTTYPEMASK 0x0000000f
|
|
42
|
+
|
|
43
|
+
namespace SVF
|
|
44
|
+
{
|
|
45
|
+
|
|
46
|
+
/*!
|
|
47
|
+
* Bug Detector Recoder
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class BugEvent
|
|
52
|
+
{
|
|
53
|
+
public:
|
|
54
|
+
enum EventType
|
|
55
|
+
{
|
|
56
|
+
Branch = 0x1,
|
|
57
|
+
Caller = 0x2,
|
|
58
|
+
CallSite = 0x3,
|
|
59
|
+
Loop = 0x4,
|
|
60
|
+
SourceInst = 0x5
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
protected:
|
|
64
|
+
u32_t typeAndInfoFlag;
|
|
65
|
+
const SVFInstruction *eventInst;
|
|
66
|
+
|
|
67
|
+
public:
|
|
68
|
+
BugEvent(u32_t typeAndInfoFlag, const SVFInstruction *eventInst): typeAndInfoFlag(typeAndInfoFlag), eventInst(eventInst) { };
|
|
69
|
+
virtual ~BugEvent() = default;
|
|
70
|
+
|
|
71
|
+
inline u32_t getEventType() const
|
|
72
|
+
{
|
|
73
|
+
return typeAndInfoFlag & EVENTTYPEMASK;
|
|
74
|
+
}
|
|
75
|
+
virtual const std::string getEventDescription() const;
|
|
76
|
+
virtual const std::string getFuncName() const;
|
|
77
|
+
virtual const std::string getEventLoc() const;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
class GenericBug
|
|
81
|
+
{
|
|
82
|
+
public:
|
|
83
|
+
typedef std::vector<BugEvent> EventStack;
|
|
84
|
+
|
|
85
|
+
public:
|
|
86
|
+
enum BugType {FULLBUFOVERFLOW, PARTIALBUFOVERFLOW, NEVERFREE, PARTIALLEAK, DOUBLEFREE, FILENEVERCLOSE, FILEPARTIALCLOSE};
|
|
87
|
+
|
|
88
|
+
protected:
|
|
89
|
+
BugType bugType;
|
|
90
|
+
const EventStack bugEventStack;
|
|
91
|
+
|
|
92
|
+
public:
|
|
93
|
+
/// note: should be initialized with a bugEventStack
|
|
94
|
+
GenericBug(BugType bugType, const EventStack &bugEventStack):
|
|
95
|
+
bugType(bugType), bugEventStack(bugEventStack)
|
|
96
|
+
{
|
|
97
|
+
assert(bugEventStack.size() != 0 && "bugEventStack should NOT be empty!");
|
|
98
|
+
}
|
|
99
|
+
virtual ~GenericBug() = default;
|
|
100
|
+
//GenericBug(const GenericBug &) = delete;
|
|
101
|
+
/// returns bug type
|
|
102
|
+
inline BugType getBugType() const
|
|
103
|
+
{
|
|
104
|
+
return bugType;
|
|
105
|
+
}
|
|
106
|
+
/// returns bug location as json format string
|
|
107
|
+
const std::string getLoc() const;
|
|
108
|
+
/// return bug source function name
|
|
109
|
+
const std::string getFuncName() const;
|
|
110
|
+
|
|
111
|
+
inline const EventStack& getEventStack() const
|
|
112
|
+
{
|
|
113
|
+
return bugEventStack;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
virtual cJSON *getBugDescription() const = 0;
|
|
117
|
+
virtual void printBugToTerminal() const = 0;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
class BufferOverflowBug: public GenericBug
|
|
121
|
+
{
|
|
122
|
+
protected:
|
|
123
|
+
s64_t allocLowerBound, allocUpperBound, accessLowerBound, accessUpperBound;
|
|
124
|
+
|
|
125
|
+
public:
|
|
126
|
+
BufferOverflowBug(GenericBug::BugType bugType, const EventStack &eventStack,
|
|
127
|
+
s64_t allocLowerBound, s64_t allocUpperBound,
|
|
128
|
+
s64_t accessLowerBound, s64_t accessUpperBound):
|
|
129
|
+
GenericBug(bugType, eventStack), allocLowerBound(allocLowerBound),
|
|
130
|
+
allocUpperBound(allocUpperBound), accessLowerBound(accessLowerBound),
|
|
131
|
+
accessUpperBound(accessUpperBound) { }
|
|
132
|
+
|
|
133
|
+
cJSON *getBugDescription() const;
|
|
134
|
+
void printBugToTerminal() const;
|
|
135
|
+
|
|
136
|
+
/// ClassOf
|
|
137
|
+
static inline bool classof(const GenericBug *bug)
|
|
138
|
+
{
|
|
139
|
+
return bug->getBugType() == GenericBug::PARTIALBUFOVERFLOW || bug->getBugType() == GenericBug::FULLBUFOVERFLOW;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
class FullBufferOverflowBug: public BufferOverflowBug
|
|
144
|
+
{
|
|
145
|
+
public:
|
|
146
|
+
FullBufferOverflowBug(const EventStack &eventStack,
|
|
147
|
+
s64_t allocLowerBound, s64_t allocUpperBound,
|
|
148
|
+
s64_t accessLowerBound, s64_t accessUpperBound):
|
|
149
|
+
BufferOverflowBug(GenericBug::FULLBUFOVERFLOW, eventStack, allocLowerBound,
|
|
150
|
+
allocUpperBound, accessLowerBound, accessUpperBound) { }
|
|
151
|
+
|
|
152
|
+
/// ClassOf
|
|
153
|
+
static inline bool classof(const GenericBug *bug)
|
|
154
|
+
{
|
|
155
|
+
return bug->getBugType() == GenericBug::FULLBUFOVERFLOW;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
class PartialBufferOverflowBug: public BufferOverflowBug
|
|
160
|
+
{
|
|
161
|
+
public:
|
|
162
|
+
PartialBufferOverflowBug( const EventStack &eventStack,
|
|
163
|
+
s64_t allocLowerBound, s64_t allocUpperBound,
|
|
164
|
+
s64_t accessLowerBound, s64_t accessUpperBound):
|
|
165
|
+
BufferOverflowBug(GenericBug::PARTIALBUFOVERFLOW, eventStack, allocLowerBound,
|
|
166
|
+
allocUpperBound, accessLowerBound, accessUpperBound) { }
|
|
167
|
+
|
|
168
|
+
/// ClassOf
|
|
169
|
+
static inline bool classof(const GenericBug *bug)
|
|
170
|
+
{
|
|
171
|
+
return bug->getBugType() == GenericBug::PARTIALBUFOVERFLOW;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
class NeverFreeBug : public GenericBug
|
|
176
|
+
{
|
|
177
|
+
public:
|
|
178
|
+
NeverFreeBug(const EventStack &bugEventStack):
|
|
179
|
+
GenericBug(GenericBug::NEVERFREE, bugEventStack) { };
|
|
180
|
+
|
|
181
|
+
cJSON *getBugDescription() const;
|
|
182
|
+
void printBugToTerminal() const;
|
|
183
|
+
|
|
184
|
+
/// ClassOf
|
|
185
|
+
static inline bool classof(const GenericBug *bug)
|
|
186
|
+
{
|
|
187
|
+
return bug->getBugType() == GenericBug::NEVERFREE;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
class PartialLeakBug : public GenericBug
|
|
192
|
+
{
|
|
193
|
+
public:
|
|
194
|
+
PartialLeakBug(const EventStack &bugEventStack):
|
|
195
|
+
GenericBug(GenericBug::PARTIALLEAK, bugEventStack) { }
|
|
196
|
+
|
|
197
|
+
cJSON *getBugDescription() const;
|
|
198
|
+
void printBugToTerminal() const;
|
|
199
|
+
|
|
200
|
+
/// ClassOf
|
|
201
|
+
static inline bool classof(const GenericBug *bug)
|
|
202
|
+
{
|
|
203
|
+
return bug->getBugType() == GenericBug::PARTIALLEAK;
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
class DoubleFreeBug : public GenericBug
|
|
208
|
+
{
|
|
209
|
+
public:
|
|
210
|
+
DoubleFreeBug(const EventStack &bugEventStack):
|
|
211
|
+
GenericBug(GenericBug::PARTIALLEAK, bugEventStack) { }
|
|
212
|
+
|
|
213
|
+
cJSON *getBugDescription() const;
|
|
214
|
+
void printBugToTerminal() const;
|
|
215
|
+
|
|
216
|
+
/// ClassOf
|
|
217
|
+
static inline bool classof(const GenericBug *bug)
|
|
218
|
+
{
|
|
219
|
+
return bug->getBugType() == GenericBug::DOUBLEFREE;
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
class FileNeverCloseBug : public GenericBug
|
|
224
|
+
{
|
|
225
|
+
public:
|
|
226
|
+
FileNeverCloseBug(const EventStack &bugEventStack):
|
|
227
|
+
GenericBug(GenericBug::NEVERFREE, bugEventStack) { };
|
|
228
|
+
|
|
229
|
+
cJSON *getBugDescription() const;
|
|
230
|
+
void printBugToTerminal() const;
|
|
231
|
+
|
|
232
|
+
/// ClassOf
|
|
233
|
+
static inline bool classof(const GenericBug *bug)
|
|
234
|
+
{
|
|
235
|
+
return bug->getBugType() == GenericBug::FILENEVERCLOSE;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
class FilePartialCloseBug : public GenericBug
|
|
240
|
+
{
|
|
241
|
+
public:
|
|
242
|
+
FilePartialCloseBug(const EventStack &bugEventStack):
|
|
243
|
+
GenericBug(GenericBug::PARTIALLEAK, bugEventStack) { }
|
|
244
|
+
|
|
245
|
+
cJSON *getBugDescription() const;
|
|
246
|
+
void printBugToTerminal() const;
|
|
247
|
+
|
|
248
|
+
/// ClassOf
|
|
249
|
+
static inline bool classof(const GenericBug *bug)
|
|
250
|
+
{
|
|
251
|
+
return bug->getBugType() == GenericBug::FILEPARTIALCLOSE;
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
class SVFBugReport
|
|
256
|
+
{
|
|
257
|
+
public:
|
|
258
|
+
SVFBugReport() = default;
|
|
259
|
+
~SVFBugReport();
|
|
260
|
+
typedef SVF::Set<const GenericBug *> BugSet;
|
|
261
|
+
|
|
262
|
+
protected:
|
|
263
|
+
BugSet bugSet; // maintain bugs
|
|
264
|
+
|
|
265
|
+
public:
|
|
266
|
+
|
|
267
|
+
/*
|
|
268
|
+
* function: pass bug type (i.e., GenericBug::NEVERFREE) and eventStack as parameter,
|
|
269
|
+
* it will add the bug into bugQueue.
|
|
270
|
+
* usage: addSaberBug(GenericBug::NEVERFREE, eventStack)
|
|
271
|
+
*/
|
|
272
|
+
void addSaberBug(GenericBug::BugType bugType, const GenericBug::EventStack &eventStack)
|
|
273
|
+
{
|
|
274
|
+
/// create and add the bug
|
|
275
|
+
GenericBug *newBug = nullptr;
|
|
276
|
+
switch(bugType)
|
|
277
|
+
{
|
|
278
|
+
case GenericBug::NEVERFREE:
|
|
279
|
+
{
|
|
280
|
+
newBug = new NeverFreeBug(eventStack);
|
|
281
|
+
bugSet.insert(newBug);
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
case GenericBug::PARTIALLEAK:
|
|
285
|
+
{
|
|
286
|
+
newBug = new PartialLeakBug(eventStack);
|
|
287
|
+
bugSet.insert(newBug);
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
case GenericBug::DOUBLEFREE:
|
|
291
|
+
{
|
|
292
|
+
newBug = new DoubleFreeBug(eventStack);
|
|
293
|
+
bugSet.insert(newBug);
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
case GenericBug::FILENEVERCLOSE:
|
|
297
|
+
{
|
|
298
|
+
newBug = new FileNeverCloseBug(eventStack);
|
|
299
|
+
bugSet.insert(newBug);
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
case GenericBug::FILEPARTIALCLOSE:
|
|
303
|
+
{
|
|
304
|
+
newBug = new FilePartialCloseBug(eventStack);
|
|
305
|
+
bugSet.insert(newBug);
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
default:
|
|
309
|
+
{
|
|
310
|
+
assert(false && "saber does NOT have this bug type!");
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// when add a bug, also print it to terminal
|
|
316
|
+
newBug->printBugToTerminal();
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/*
|
|
320
|
+
* function: pass bug type (i.e., GenericBug::FULLBUFOVERFLOW) and eventStack as parameter,
|
|
321
|
+
* it will add the bug into bugQueue.
|
|
322
|
+
* usage: addAbsExecBug(GenericBug::FULLBUFOVERFLOW, eventStack, 0, 10, 11, 11)
|
|
323
|
+
*/
|
|
324
|
+
void addAbsExecBug(GenericBug::BugType bugType, const GenericBug::EventStack &eventStack,
|
|
325
|
+
s64_t allocLowerBound, s64_t allocUpperBound, s64_t accessLowerBound, s64_t accessUpperBound)
|
|
326
|
+
{
|
|
327
|
+
/// add bugs
|
|
328
|
+
GenericBug *newBug = nullptr;
|
|
329
|
+
switch(bugType)
|
|
330
|
+
{
|
|
331
|
+
case GenericBug::FULLBUFOVERFLOW:
|
|
332
|
+
{
|
|
333
|
+
newBug = new FullBufferOverflowBug(eventStack, allocLowerBound, allocUpperBound, accessLowerBound, accessUpperBound);
|
|
334
|
+
bugSet.insert(newBug);
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
case GenericBug::PARTIALBUFOVERFLOW:
|
|
338
|
+
{
|
|
339
|
+
newBug = new PartialBufferOverflowBug(eventStack, allocLowerBound, allocUpperBound, accessLowerBound, accessUpperBound);
|
|
340
|
+
bugSet.insert(newBug);
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
default:
|
|
344
|
+
{
|
|
345
|
+
assert(false && "Abstract Execution does NOT hava his bug type!");
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// when add a bug, also print it to terminal
|
|
351
|
+
newBug->printBugToTerminal();
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/*
|
|
355
|
+
* function: pass file path, open the file and dump bug report as JSON format
|
|
356
|
+
* usage: dumpToFile("/path/to/file")
|
|
357
|
+
*/
|
|
358
|
+
void dumpToJsonFile(const std::string& filePath);
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
#endif
|
|
@@ -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
|
+
GenericBug::EventStack eventStack;
|
|
43
|
+
slice->evalFinalCond2Event(eventStack);
|
|
44
|
+
eventStack.push_back(
|
|
45
|
+
BugEvent(BugEvent::SourceInst, getSrcCSID(slice->getSource())->getCallSite()));
|
|
46
|
+
report.addSaberBug(GenericBug::DOUBLEFREE, eventStack);
|
|
47
47
|
}
|
|
48
48
|
if(Options::ValidateTests())
|
|
49
49
|
testsValidation(slice);
|
|
@@ -33,31 +33,24 @@ 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
|
+
GenericBug::EventStack eventStack =
|
|
43
|
+
{
|
|
44
|
+
BugEvent(BugEvent::SourceInst, getSrcCSID(slice->getSource())->getCallSite())
|
|
45
|
+
};
|
|
46
|
+
report.addSaberBug(GenericBug::FILENEVERCLOSE, eventStack);
|
|
56
47
|
}
|
|
57
48
|
else if (isAllPathReachable() == false && isSomePathReachable() == true)
|
|
58
49
|
{
|
|
59
|
-
|
|
60
|
-
|
|
50
|
+
GenericBug::EventStack eventStack;
|
|
51
|
+
slice->evalFinalCond2Event(eventStack);
|
|
52
|
+
eventStack.push_back(
|
|
53
|
+
BugEvent(BugEvent::SourceInst, getSrcCSID(slice->getSource())->getCallSite()));
|
|
54
|
+
report.addSaberBug(GenericBug::FILEPARTIALCLOSE, eventStack);
|
|
61
55
|
}
|
|
62
|
-
|
|
63
56
|
}
|
|
@@ -146,33 +146,26 @@ 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
|
+
GenericBug::EventStack eventStack =
|
|
156
|
+
{
|
|
157
|
+
BugEvent(BugEvent::SourceInst, getSrcCSID(slice->getSource())->getCallSite())
|
|
158
|
+
};
|
|
159
|
+
report.addSaberBug(GenericBug::NEVERFREE, eventStack);
|
|
171
160
|
}
|
|
172
161
|
else if (isAllPathReachable() == false && isSomePathReachable() == true)
|
|
173
162
|
{
|
|
174
|
-
|
|
175
|
-
|
|
163
|
+
// partial leakage
|
|
164
|
+
GenericBug::EventStack eventStack;
|
|
165
|
+
slice->evalFinalCond2Event(eventStack);
|
|
166
|
+
eventStack.push_back(
|
|
167
|
+
BugEvent(BugEvent::SourceInst, getSrcCSID(slice->getSource())->getCallSite()));
|
|
168
|
+
report.addSaberBug(GenericBug::PARTIALLEAK, eventStack);
|
|
176
169
|
}
|
|
177
170
|
|
|
178
171
|
if(Options::ValidateTests())
|
|
@@ -146,6 +146,20 @@ 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
|
+
for(NodeBS::iterator it = elems.begin(), eit = elems.end(); it!=eit; ++it)
|
|
153
|
+
{
|
|
154
|
+
const SVFInstruction* tinst = pathAllocator->getCondInst(*it);
|
|
155
|
+
if(pathAllocator->isNegCond(*it))
|
|
156
|
+
eventStack.push_back(BugEvent(
|
|
157
|
+
BugEvent::Branch|((((u32_t)false) << 4) & BRANCHFLAGMASK), tinst));
|
|
158
|
+
else
|
|
159
|
+
eventStack.push_back(BugEvent(
|
|
160
|
+
BugEvent::Branch|((((u32_t)true) << 4) & BRANCHFLAGMASK), tinst));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
149
163
|
|
|
150
164
|
/*!
|
|
151
165
|
* Evaluate Atoms of a condition
|
|
@@ -160,8 +174,9 @@ std::string ProgSlice::evalFinalCond() const
|
|
|
160
174
|
{
|
|
161
175
|
std::string str;
|
|
162
176
|
std::stringstream rawstr(str);
|
|
163
|
-
NodeBS elems = pathAllocator->exactCondElem(finalCond);
|
|
164
177
|
Set<std::string> locations;
|
|
178
|
+
NodeBS elems = pathAllocator->exactCondElem(finalCond);
|
|
179
|
+
|
|
165
180
|
for(NodeBS::iterator it = elems.begin(), eit = elems.end(); it!=eit; ++it)
|
|
166
181
|
{
|
|
167
182
|
const SVFInstruction* tinst = pathAllocator->getCondInst(*it);
|
|
@@ -170,6 +185,7 @@ std::string ProgSlice::evalFinalCond() const
|
|
|
170
185
|
else
|
|
171
186
|
locations.insert(tinst->getSourceLoc()+"|True");
|
|
172
187
|
}
|
|
188
|
+
|
|
173
189
|
/// print leak path after eliminating duplicated element
|
|
174
190
|
for(Set<std::string>::iterator iter = locations.begin(), eiter = locations.end();
|
|
175
191
|
iter!=eiter; ++iter)
|
|
@@ -0,0 +1,399 @@
|
|
|
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 BugEvent&sourceInstEvent = bugEventStack.at(bugEventStack.size() -1);
|
|
41
|
+
assert(sourceInstEvent.getEventType() == BugEvent::SourceInst && "bugEventStack top should be a SourceInst event");
|
|
42
|
+
return sourceInstEvent.getEventLoc();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const std::string GenericBug::getFuncName() const
|
|
46
|
+
{
|
|
47
|
+
const BugEvent&sourceInstEvent = bugEventStack.at(bugEventStack.size() -1);
|
|
48
|
+
assert(sourceInstEvent.getEventType() == BugEvent::SourceInst && "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 event : bugEventStack)
|
|
88
|
+
{
|
|
89
|
+
switch(event.getEventType())
|
|
90
|
+
{
|
|
91
|
+
case BugEvent::CallSite:
|
|
92
|
+
{
|
|
93
|
+
SVFUtil::errs() << "\t\t callsite at : ( " << event.getEventLoc() << " )\n";
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
default:
|
|
97
|
+
{
|
|
98
|
+
// TODO: implement more events when needed
|
|
99
|
+
break;
|
|
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
|
+
|
|
128
|
+
cJSON *branchCondition = cJSON_CreateString((*eventIt).getEventDescription().c_str());
|
|
129
|
+
|
|
130
|
+
cJSON_AddItemToObject(newBranch, "BranchLoc", branchLoc);
|
|
131
|
+
cJSON_AddItemToObject(newBranch, "BranchCond", branchCondition);
|
|
132
|
+
|
|
133
|
+
cJSON_AddItemToArray(pathInfo, newBranch);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
cJSON_AddItemToObject(bugDescription, "ConditionalFreePath", pathInfo);
|
|
137
|
+
|
|
138
|
+
return bugDescription;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
void PartialLeakBug::printBugToTerminal() const
|
|
142
|
+
{
|
|
143
|
+
SVFUtil::errs() << SVFUtil::bugMsg2("\t PartialLeak :") << " memory allocation at : ("
|
|
144
|
+
<< GenericBug::getLoc() << ")\n";
|
|
145
|
+
|
|
146
|
+
SVFUtil::errs() << "\t\t conditional free path: \n";
|
|
147
|
+
auto lastBranchEventIt = bugEventStack.end() - 1;
|
|
148
|
+
for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
|
|
149
|
+
{
|
|
150
|
+
SVFUtil::errs() << "\t\t --> (" << (*eventIt).getEventLoc() << "|" << (*eventIt).getEventDescription() << ") \n";
|
|
151
|
+
}
|
|
152
|
+
SVFUtil::errs() << "\n";
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
cJSON * DoubleFreeBug::getBugDescription() const
|
|
156
|
+
{
|
|
157
|
+
cJSON *bugDescription = cJSON_CreateObject();
|
|
158
|
+
|
|
159
|
+
cJSON *pathInfo = cJSON_CreateArray();
|
|
160
|
+
auto lastBranchEventIt = bugEventStack.end() - 1;
|
|
161
|
+
for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
|
|
162
|
+
{
|
|
163
|
+
cJSON *newBranch = cJSON_CreateObject();
|
|
164
|
+
cJSON *branchLoc = cJSON_Parse((*eventIt).getEventLoc().c_str());
|
|
165
|
+
if(branchLoc == nullptr) branchLoc = cJSON_CreateObject();
|
|
166
|
+
cJSON *branchCondition = cJSON_CreateString((*eventIt).getEventDescription().c_str());
|
|
167
|
+
|
|
168
|
+
cJSON_AddItemToObject(newBranch, "BranchLoc", branchLoc);
|
|
169
|
+
cJSON_AddItemToObject(newBranch, "BranchCond", branchCondition);
|
|
170
|
+
|
|
171
|
+
cJSON_AddItemToArray(pathInfo, newBranch);
|
|
172
|
+
}
|
|
173
|
+
cJSON_AddItemToObject(bugDescription, "DoubleFreePath", pathInfo);
|
|
174
|
+
|
|
175
|
+
return bugDescription;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
void DoubleFreeBug::printBugToTerminal() const
|
|
179
|
+
{
|
|
180
|
+
SVFUtil::errs() << SVFUtil::bugMsg2("\t Double Free :") << " memory allocation at : ("
|
|
181
|
+
<< GenericBug::getLoc() << ")\n";
|
|
182
|
+
|
|
183
|
+
SVFUtil::errs() << "\t\t double free path: \n";
|
|
184
|
+
auto lastBranchEventIt = bugEventStack.end() - 1;
|
|
185
|
+
for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
|
|
186
|
+
{
|
|
187
|
+
SVFUtil::errs() << "\t\t --> (" << (*eventIt).getEventLoc() << "|" << (*eventIt).getEventDescription() << ") \n";
|
|
188
|
+
}
|
|
189
|
+
SVFUtil::errs() << "\n";
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
cJSON * FileNeverCloseBug::getBugDescription() const
|
|
193
|
+
{
|
|
194
|
+
cJSON *bugDescription = cJSON_CreateObject();
|
|
195
|
+
return bugDescription;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
void FileNeverCloseBug::printBugToTerminal() const
|
|
199
|
+
{
|
|
200
|
+
SVFUtil::errs() << SVFUtil::bugMsg1("\t FileNeverClose :") << " file open location at : ("
|
|
201
|
+
<< GenericBug::getLoc() << ")\n";
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
cJSON * FilePartialCloseBug::getBugDescription() const
|
|
205
|
+
{
|
|
206
|
+
cJSON *bugDescription = cJSON_CreateObject();
|
|
207
|
+
|
|
208
|
+
cJSON *pathInfo = cJSON_CreateArray();
|
|
209
|
+
|
|
210
|
+
auto lastBranchEventIt = bugEventStack.end() - 1;
|
|
211
|
+
for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
|
|
212
|
+
{
|
|
213
|
+
cJSON *newBranch = cJSON_CreateObject();
|
|
214
|
+
cJSON *branchLoc = cJSON_Parse((*eventIt).getEventLoc().c_str());
|
|
215
|
+
if(branchLoc == nullptr) branchLoc = cJSON_CreateObject();
|
|
216
|
+
cJSON *branchCondition = cJSON_CreateString((*eventIt).getEventDescription().c_str());
|
|
217
|
+
|
|
218
|
+
cJSON_AddItemToObject(newBranch, "BranchLoc", branchLoc);
|
|
219
|
+
cJSON_AddItemToObject(newBranch, "BranchCond", branchCondition);
|
|
220
|
+
|
|
221
|
+
cJSON_AddItemToArray(pathInfo, newBranch);
|
|
222
|
+
}
|
|
223
|
+
cJSON_AddItemToObject(bugDescription, "ConditionalFileClosePath", pathInfo);
|
|
224
|
+
|
|
225
|
+
return bugDescription;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
void FilePartialCloseBug::printBugToTerminal() const
|
|
229
|
+
{
|
|
230
|
+
SVFUtil::errs() << SVFUtil::bugMsg2("\t PartialFileClose :") << " file open location at : ("
|
|
231
|
+
<< GenericBug::getLoc() << ")\n";
|
|
232
|
+
|
|
233
|
+
SVFUtil::errs() << "\t\t conditional file close path: \n";
|
|
234
|
+
auto lastBranchEventIt = bugEventStack.end() - 1;
|
|
235
|
+
for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
|
|
236
|
+
{
|
|
237
|
+
SVFUtil::errs() << "\t\t --> (" << (*eventIt).getEventLoc() << "|" << (*eventIt).getEventDescription() << ") \n";
|
|
238
|
+
}
|
|
239
|
+
SVFUtil::errs() << "\n";
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const std::string BugEvent::getFuncName() const
|
|
243
|
+
{
|
|
244
|
+
return eventInst->getFunction()->getName();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const std::string BugEvent::getEventLoc() const
|
|
248
|
+
{
|
|
249
|
+
return eventInst->getSourceLoc();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const std::string BugEvent::getEventDescription() const
|
|
253
|
+
{
|
|
254
|
+
switch(getEventType())
|
|
255
|
+
{
|
|
256
|
+
case BugEvent::Branch:
|
|
257
|
+
{
|
|
258
|
+
if (typeAndInfoFlag & BRANCHFLAGMASK)
|
|
259
|
+
{
|
|
260
|
+
return "True";
|
|
261
|
+
}
|
|
262
|
+
else
|
|
263
|
+
{
|
|
264
|
+
return "False";
|
|
265
|
+
}
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
case BugEvent::CallSite:
|
|
269
|
+
{
|
|
270
|
+
std::string description("calls ");
|
|
271
|
+
const SVFFunction *callee = SVFUtil::getCallee(eventInst);
|
|
272
|
+
if(callee == nullptr)
|
|
273
|
+
{
|
|
274
|
+
description += "<unknown>";
|
|
275
|
+
}
|
|
276
|
+
else
|
|
277
|
+
{
|
|
278
|
+
description += callee->getName();
|
|
279
|
+
}
|
|
280
|
+
return description;
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
case BugEvent::SourceInst:
|
|
284
|
+
{
|
|
285
|
+
return "None";
|
|
286
|
+
}
|
|
287
|
+
default:
|
|
288
|
+
{
|
|
289
|
+
assert(false && "No such type of event!");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
SVFBugReport::~SVFBugReport()
|
|
295
|
+
{
|
|
296
|
+
for(auto bugIt: bugSet)
|
|
297
|
+
{
|
|
298
|
+
delete bugIt;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
void SVFBugReport::dumpToJsonFile(const std::string& filePath)
|
|
303
|
+
{
|
|
304
|
+
std::map<u32_t, std::string> eventType2Str =
|
|
305
|
+
{
|
|
306
|
+
{BugEvent::CallSite, "call site"},
|
|
307
|
+
{BugEvent::Caller, "caller"},
|
|
308
|
+
{BugEvent::Loop, "loop"},
|
|
309
|
+
{BugEvent::Branch, "branch"}
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
std::map<GenericBug::BugType, std::string> bugType2Str =
|
|
313
|
+
{
|
|
314
|
+
{GenericBug::FULLBUFOVERFLOW, "Full Buffer Overflow"},
|
|
315
|
+
{GenericBug::PARTIALBUFOVERFLOW, "Partial Buffer Overflow"},
|
|
316
|
+
{GenericBug::NEVERFREE, "Never Free"},
|
|
317
|
+
{GenericBug::PARTIALLEAK, "Partial Leak"},
|
|
318
|
+
{GenericBug::FILENEVERCLOSE, "File Never Close"},
|
|
319
|
+
{GenericBug::FILEPARTIALCLOSE, "File Partial Close"},
|
|
320
|
+
{GenericBug::DOUBLEFREE, "Double Free"}
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
ofstream jsonFile(filePath, ios::out);
|
|
324
|
+
|
|
325
|
+
jsonFile << "{";
|
|
326
|
+
|
|
327
|
+
size_t commaCounter = bugSet.size() - 1; // comma num needed
|
|
328
|
+
for(auto bugPtr : bugSet)
|
|
329
|
+
{
|
|
330
|
+
cJSON *singleBug = cJSON_CreateObject();
|
|
331
|
+
|
|
332
|
+
/// add bug information to json
|
|
333
|
+
cJSON *bugType = cJSON_CreateString(bugType2Str[bugPtr->getBugType()].c_str());
|
|
334
|
+
cJSON_AddItemToObject(singleBug, "DefectType", bugType);
|
|
335
|
+
|
|
336
|
+
cJSON *bugLoc = cJSON_Parse(bugPtr->getLoc().c_str());
|
|
337
|
+
if(bugLoc == nullptr)
|
|
338
|
+
{
|
|
339
|
+
bugLoc = cJSON_CreateObject();
|
|
340
|
+
}
|
|
341
|
+
cJSON_AddItemToObject(singleBug, "Location", bugLoc);
|
|
342
|
+
|
|
343
|
+
cJSON *bugFunction = cJSON_CreateString(bugPtr->getFuncName().c_str());
|
|
344
|
+
cJSON_AddItemToObject(singleBug, "Function", bugFunction);
|
|
345
|
+
|
|
346
|
+
cJSON_AddItemToObject(singleBug, "Description", bugPtr->getBugDescription());
|
|
347
|
+
|
|
348
|
+
/// add event information to json
|
|
349
|
+
cJSON *eventList = cJSON_CreateArray();
|
|
350
|
+
const GenericBug::EventStack &bugEventStack = bugPtr->getEventStack();
|
|
351
|
+
if(BufferOverflowBug::classof(bugPtr))
|
|
352
|
+
{
|
|
353
|
+
// add only when bug is context sensitive
|
|
354
|
+
for(const BugEvent&event : bugEventStack)
|
|
355
|
+
{
|
|
356
|
+
if (event.getEventType() == BugEvent::SourceInst)
|
|
357
|
+
{
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
cJSON *singleEvent = cJSON_CreateObject();
|
|
362
|
+
//event type
|
|
363
|
+
cJSON *eventType = cJSON_CreateString(eventType2Str[event.getEventType()].c_str());
|
|
364
|
+
cJSON_AddItemToObject(singleEvent, "EventType", eventType);
|
|
365
|
+
//function name
|
|
366
|
+
cJSON *eventFunc = cJSON_CreateString(event.getFuncName().c_str());
|
|
367
|
+
cJSON_AddItemToObject(singleEvent, "Function", eventFunc);
|
|
368
|
+
//event loc
|
|
369
|
+
cJSON *eventLoc = cJSON_Parse(event.getEventLoc().c_str());
|
|
370
|
+
if(eventLoc == nullptr)
|
|
371
|
+
{
|
|
372
|
+
eventLoc = cJSON_CreateObject();
|
|
373
|
+
}
|
|
374
|
+
cJSON_AddItemToObject(singleEvent, "Location", eventLoc);
|
|
375
|
+
//event description
|
|
376
|
+
cJSON *eventDescription = cJSON_CreateString(event.getEventDescription().c_str());
|
|
377
|
+
cJSON_AddItemToObject(singleEvent, "Description", eventDescription);
|
|
378
|
+
|
|
379
|
+
cJSON_AddItemToArray(eventList, singleEvent);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
cJSON_AddItemToObject(singleBug, "Events", eventList);
|
|
383
|
+
|
|
384
|
+
/// dump single bug to json str and write to file
|
|
385
|
+
char *singleBugStr = cJSON_Print(singleBug);
|
|
386
|
+
jsonFile << singleBugStr;
|
|
387
|
+
if (commaCounter != 0)
|
|
388
|
+
{
|
|
389
|
+
jsonFile << ",\n";
|
|
390
|
+
}
|
|
391
|
+
commaCounter --;
|
|
392
|
+
|
|
393
|
+
/// destroy the cJSON object
|
|
394
|
+
cJSON_Delete(singleBug);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
jsonFile << "}";
|
|
398
|
+
jsonFile.close();
|
|
399
|
+
}
|
|
@@ -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
|
}
|