svf-tools 1.0.698 → 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/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/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": {
|
|
@@ -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
|
|
@@ -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
|
}
|