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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svf-tools",
3
- "version": "1.0.698",
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": {
@@ -73,8 +73,6 @@ public:
73
73
  }
74
74
  /// Report file/close bugs
75
75
  void reportBug(ProgSlice* slice);
76
- void reportNeverClose(const SVFGNode* src);
77
- void reportPartialClose(const SVFGNode* src);
78
76
  };
79
77
 
80
78
  } // End namespace SVF
@@ -93,8 +93,6 @@ protected:
93
93
  /// Report leaks
94
94
  //@{
95
95
  virtual void reportBug(ProgSlice* slice) override;
96
- void reportNeverFree(const SVFGNode* src);
97
- void reportPartialLeak(const SVFGNode* src);
98
96
  //@}
99
97
 
100
98
  /// Validate test cases for regression test purpose
@@ -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
- const SVFGNode* src = slice->getSource();
43
- const CallICFGNode* cs = getSrcCSID(src);
44
- SVFUtil::errs() << bugMsg2("\t Double Free :") << " memory allocation at : ("
45
- << cs->getCallSite()->getSourceLoc() << ")\n";
46
- SVFUtil::errs() << "\t\t double free path: \n" << slice->evalFinalCond() << "\n";
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
- reportNeverClose(slice->getSource());
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
- reportPartialClose(slice->getSource());
60
- SVFUtil::errs() << "\t\t conditional file close path: \n" << slice->evalFinalCond() << "\n";
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
- reportNeverFree(slice->getSource());
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
- reportPartialLeak(slice->getSource());
175
- SVFUtil::errs() << "\t\t conditional free path: \n" << slice->evalFinalCond() << "\n";
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)
@@ -105,7 +105,6 @@ void SrcSnkDDA::analyze(SVFModule* module)
105
105
 
106
106
  reportBug(getCurSlice());
107
107
  }
108
-
109
108
  finalize();
110
109
 
111
110
  }
@@ -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 << " cl: " << Column << " fl: " << File;
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 << "in line: " << SP->getLine() << " file: " << SP->getFilename().str();
587
+ rawstr << "\"ln\": " << SP->getLine() << ", \"file\": \"" << SP->getFilename().str() << "\"";
588
588
  }
589
589
  return rawstr.str();
590
590
  }