Static Value-Flow Analysis
SVFBugReport.cpp
Go to the documentation of this file.
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::map<GenericBug::BugType, std::string> GenericBug::BugType2Str =
39 {
40  {GenericBug::FULLBUFOVERFLOW, "Full Buffer Overflow"},
41  {GenericBug::PARTIALBUFOVERFLOW, "Partial Buffer Overflow"},
42  {GenericBug::NEVERFREE, "Never Free"},
43  {GenericBug::PARTIALLEAK, "Partial Leak"},
44  {GenericBug::FILENEVERCLOSE, "File Never Close"},
45  {GenericBug::FILEPARTIALCLOSE, "File Partial Close"},
46  {GenericBug::DOUBLEFREE, "Double Free"},
47  {GenericBug::FULLNULLPTRDEREFERENCE, "Full Null Ptr Dereference"},
48  {GenericBug::PARTIALNULLPTRDEREFERENCE, "Partial Null Ptr Dereference"}
49 };
50 
51 const std::string GenericBug::getLoc() const
52 {
53  const SVFBugEvent&sourceInstEvent = bugEventStack.at(bugEventStack.size() -1);
54  return sourceInstEvent.getEventLoc();
55 }
56 
57 const std::string GenericBug::getFuncName() const
58 {
59  const SVFBugEvent&sourceInstEvent = bugEventStack.at(bugEventStack.size() -1);
60  return sourceInstEvent.getFuncName();
61 }
62 
63 cJSON *BufferOverflowBug::getBugDescription() const
64 {
65  cJSON *bugDescription = cJSON_CreateObject();
66  cJSON *allocLB = cJSON_CreateNumber(allocLowerBound);
67  cJSON *allocUB = cJSON_CreateNumber(allocUpperBound);
68  cJSON *accessLB = cJSON_CreateNumber(accessLowerBound);
69  cJSON *accessUB = cJSON_CreateNumber(accessUpperBound);
70 
71  cJSON_AddItemToObject(bugDescription, "AllocLowerBound", allocLB);
72  cJSON_AddItemToObject(bugDescription, "AllocUpperBound", allocUB);
73  cJSON_AddItemToObject(bugDescription, "AccessLowerBound", accessLB);
74  cJSON_AddItemToObject(bugDescription, "AccessUpperBound", accessUB);
75 
76  return bugDescription;
77 }
78 
79 void BufferOverflowBug::printBugToTerminal() const
80 {
81  stringstream bugInfo;
82  if(FullBufferOverflowBug::classof(this))
83  {
84  SVFUtil::errs() << SVFUtil::bugMsg1("\t Full Overflow :") << " accessing at : ("
85  << GenericBug::getLoc() << ")\n";
86 
87  }
88  else
89  {
90  SVFUtil::errs() << SVFUtil::bugMsg1("\t Partial Overflow :") << " accessing at : ("
91  << GenericBug::getLoc() << ")\n";
92  }
93  bugInfo << "\t\t allocate size : [" << allocLowerBound << ", " << allocUpperBound << "], ";
94  bugInfo << "access size : [" << accessLowerBound << ", " << accessUpperBound << "]\n";
95  SVFUtil::errs() << "\t\t Info : \n" << bugInfo.str();
96  SVFUtil::errs() << "\t\t Events : \n";
97 
98  for(auto event : bugEventStack)
99  {
100  switch(event.getEventType())
101  {
102  case SVFBugEvent::CallSite:
103  {
104  SVFUtil::errs() << "\t\t callsite at : ( " << event.getEventLoc() << " )\n";
105  break;
106  }
107  default:
108  {
109  // TODO: implement more events when needed
110  break;
111  }
112  }
113  }
114 }
115 
116 cJSON * NeverFreeBug::getBugDescription() const
117 {
118  cJSON *bugDescription = cJSON_CreateObject();
119  return bugDescription;
120 }
121 
122 void NeverFreeBug::printBugToTerminal() const
123 {
124  SVFUtil::errs() << SVFUtil::bugMsg1("\t NeverFree :") << " memory allocation at : ("
125  << GenericBug::getLoc() << ")\n";
126 }
127 
128 cJSON * PartialLeakBug::getBugDescription() const
129 {
130  cJSON *bugDescription = cJSON_CreateObject();
131  cJSON *pathInfo = cJSON_CreateArray();
132  auto lastBranchEventIt = bugEventStack.end() - 1;
133  for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
134  {
135  cJSON *newBranch = cJSON_CreateObject();
136  cJSON *branchLoc = cJSON_Parse((*eventIt).getEventLoc().c_str());
137  if(branchLoc == nullptr) branchLoc = cJSON_CreateObject();
138 
139  cJSON *branchCondition = cJSON_CreateString((*eventIt).getEventDescription().c_str());
140 
141  cJSON_AddItemToObject(newBranch, "BranchLoc", branchLoc);
142  cJSON_AddItemToObject(newBranch, "BranchCond", branchCondition);
143 
144  cJSON_AddItemToArray(pathInfo, newBranch);
145  }
146 
147  cJSON_AddItemToObject(bugDescription, "ConditionalFreePath", pathInfo);
148 
149  return bugDescription;
150 }
151 
152 void PartialLeakBug::printBugToTerminal() const
153 {
154  SVFUtil::errs() << SVFUtil::bugMsg2("\t PartialLeak :") << " memory allocation at : ("
155  << GenericBug::getLoc() << ")\n";
156 
157  SVFUtil::errs() << "\t\t conditional free path: \n";
158  auto lastBranchEventIt = bugEventStack.end() - 1;
159  for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
160  {
161  SVFUtil::errs() << "\t\t --> (" << (*eventIt).getEventLoc() << "|" << (*eventIt).getEventDescription() << ") \n";
162  }
163  SVFUtil::errs() << "\n";
164 }
165 
166 cJSON * DoubleFreeBug::getBugDescription() const
167 {
168  cJSON *bugDescription = cJSON_CreateObject();
169 
170  cJSON *pathInfo = cJSON_CreateArray();
171  auto lastBranchEventIt = bugEventStack.end() - 1;
172  for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
173  {
174  cJSON *newBranch = cJSON_CreateObject();
175  cJSON *branchLoc = cJSON_Parse((*eventIt).getEventLoc().c_str());
176  if(branchLoc == nullptr) branchLoc = cJSON_CreateObject();
177  cJSON *branchCondition = cJSON_CreateString((*eventIt).getEventDescription().c_str());
178 
179  cJSON_AddItemToObject(newBranch, "BranchLoc", branchLoc);
180  cJSON_AddItemToObject(newBranch, "BranchCond", branchCondition);
181 
182  cJSON_AddItemToArray(pathInfo, newBranch);
183  }
184  cJSON_AddItemToObject(bugDescription, "DoubleFreePath", pathInfo);
185 
186  return bugDescription;
187 }
188 
189 void DoubleFreeBug::printBugToTerminal() const
190 {
191  SVFUtil::errs() << SVFUtil::bugMsg2("\t Double Free :") << " memory allocation at : ("
192  << GenericBug::getLoc() << ")\n";
193 
194  SVFUtil::errs() << "\t\t double free path: \n";
195  auto lastBranchEventIt = bugEventStack.end() - 1;
196  for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
197  {
198  SVFUtil::errs() << "\t\t --> (" << (*eventIt).getEventLoc() << "|" << (*eventIt).getEventDescription() << ") \n";
199  }
200  SVFUtil::errs() << "\n";
201 }
202 
203 cJSON * FileNeverCloseBug::getBugDescription() const
204 {
205  cJSON *bugDescription = cJSON_CreateObject();
206  return bugDescription;
207 }
208 
209 void FileNeverCloseBug::printBugToTerminal() const
210 {
211  SVFUtil::errs() << SVFUtil::bugMsg1("\t FileNeverClose :") << " file open location at : ("
212  << GenericBug::getLoc() << ")\n";
213 }
214 
215 cJSON * FilePartialCloseBug::getBugDescription() const
216 {
217  cJSON *bugDescription = cJSON_CreateObject();
218 
219  cJSON *pathInfo = cJSON_CreateArray();
220 
221  auto lastBranchEventIt = bugEventStack.end() - 1;
222  for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
223  {
224  cJSON *newBranch = cJSON_CreateObject();
225  cJSON *branchLoc = cJSON_Parse((*eventIt).getEventLoc().c_str());
226  if(branchLoc == nullptr) branchLoc = cJSON_CreateObject();
227  cJSON *branchCondition = cJSON_CreateString((*eventIt).getEventDescription().c_str());
228 
229  cJSON_AddItemToObject(newBranch, "BranchLoc", branchLoc);
230  cJSON_AddItemToObject(newBranch, "BranchCond", branchCondition);
231 
232  cJSON_AddItemToArray(pathInfo, newBranch);
233  }
234  cJSON_AddItemToObject(bugDescription, "ConditionalFileClosePath", pathInfo);
235 
236  return bugDescription;
237 }
238 
239 void FilePartialCloseBug::printBugToTerminal() const
240 {
241  SVFUtil::errs() << SVFUtil::bugMsg2("\t PartialFileClose :") << " file open location at : ("
242  << GenericBug::getLoc() << ")\n";
243 
244  SVFUtil::errs() << "\t\t conditional file close path: \n";
245  auto lastBranchEventIt = bugEventStack.end() - 1;
246  for(auto eventIt = bugEventStack.begin(); eventIt != lastBranchEventIt; eventIt++)
247  {
248  SVFUtil::errs() << "\t\t --> (" << (*eventIt).getEventLoc() << "|" << (*eventIt).getEventDescription() << ") \n";
249  }
250  SVFUtil::errs() << "\n";
251 }
252 
253 cJSON *FullNullPtrDereferenceBug::getBugDescription() const
254 {
255  cJSON *bugDescription = cJSON_CreateObject();
256  return bugDescription;
257 }
258 
259 void FullNullPtrDereferenceBug::printBugToTerminal() const
260 {
261  SVFUtil::errs() << SVFUtil::bugMsg2("\t FullNullPtrDereference :") << " dereference at : ("
262  << GenericBug::getLoc() << ")\n";
263 }
264 
265 cJSON *PartialNullPtrDereferenceBug::getBugDescription() const
266 {
267  cJSON *bugDescription = cJSON_CreateObject();
268  return bugDescription;
269 }
270 
271 void PartialNullPtrDereferenceBug::printBugToTerminal() const
272 {
273  SVFUtil::errs() << SVFUtil::bugMsg2("\t PartialNullPtrDereference :") << " dereference at : ("
274  << GenericBug::getLoc() << ")\n";
275 }
276 
277 const std::string SVFBugEvent::getFuncName() const
278 {
279  return eventInst->getFun()->getName();
280 }
281 
282 const std::string SVFBugEvent::getEventLoc() const
283 {
284  return eventInst->getSourceLoc();
285 }
286 
287 const std::string SVFBugEvent::getEventDescription() const
288 {
289  switch(getEventType())
290  {
291  case SVFBugEvent::Branch:
292  {
293  if (typeAndInfoFlag & BRANCHFLAGMASK)
294  {
295  return "True";
296  }
297  else
298  {
299  return "False";
300  }
301  break;
302  }
303  case SVFBugEvent::CallSite:
304  {
305  std::string description("calls ");
306  assert(SVFUtil::isa<CallICFGNode>(eventInst) && "not a call ICFGNode?");
307  const SVFFunction *callee = SVFUtil::cast<CallICFGNode>(eventInst)->getCalledFunction();
308  if(callee == nullptr)
309  {
310  description += "<unknown>";
311  }
312  else
313  {
314  description += callee->getName();
315  }
316  return description;
317  break;
318  }
319  case SVFBugEvent::SourceInst:
320  {
321  return "None";
322  }
323  default:
324  {
325  assert(false && "No such type of event!");
326  abort();
327  }
328  }
329 }
330 
331 SVFBugReport::~SVFBugReport()
332 {
333  for(auto bugIt: bugSet)
334  {
335  delete bugIt;
336  }
337 }
338 
339 void SVFBugReport::dumpToJsonFile(const std::string& filePath) const
340 {
341  std::map<u32_t, std::string> eventType2Str =
342  {
343  {SVFBugEvent::CallSite, "call site"},
344  {SVFBugEvent::Caller, "caller"},
345  {SVFBugEvent::Loop, "loop"},
346  {SVFBugEvent::Branch, "branch"}
347  };
348 
349  ofstream jsonFile(filePath, ios::out);
350 
351  jsonFile << "{\n";
352 
354  jsonFile << "\"Defects\": [\n";
355  size_t commaCounter = bugSet.size() - 1;
356  for (auto bugPtr : bugSet)
357  {
358  cJSON *singleDefect = cJSON_CreateObject();
359 
361  cJSON *bugType = cJSON_CreateString(
362  GenericBug::BugType2Str.at(bugPtr->getBugType()).c_str());
363  cJSON_AddItemToObject(singleDefect, "DefectType", bugType);
364 
365  cJSON *bugLoc = cJSON_Parse(bugPtr->getLoc().c_str());
366  if (bugLoc == nullptr)
367  {
368  bugLoc = cJSON_CreateObject();
369  }
370  cJSON_AddItemToObject(singleDefect, "Location", bugLoc);
371 
372  cJSON *bugFunction = cJSON_CreateString(
373  bugPtr->getFuncName().c_str());
374  cJSON_AddItemToObject(singleDefect, "Function", bugFunction);
375 
376  cJSON_AddItemToObject(singleDefect, "Description",
377  bugPtr->getBugDescription());
378 
380  cJSON *eventList = cJSON_CreateArray();
381  const GenericBug::EventStack &bugEventStack = bugPtr->getEventStack();
382  if (BufferOverflowBug::classof(bugPtr))
383  {
384  // Add only when bug is context sensitive
385  for (const SVFBugEvent &event : bugEventStack)
386  {
387  if (event.getEventType() == SVFBugEvent::SourceInst)
388  {
389  continue;
390  }
391 
392  cJSON *singleEvent = cJSON_CreateObject();
393  // Event type
394  cJSON *eventType = cJSON_CreateString(
395  eventType2Str[event.getEventType()].c_str());
396  cJSON_AddItemToObject(singleEvent, "EventType", eventType);
397  // Function name
398  cJSON *eventFunc = cJSON_CreateString(
399  event.getFuncName().c_str());
400  cJSON_AddItemToObject(singleEvent, "Function", eventFunc);
401  // Event loc
402  cJSON *eventLoc = cJSON_Parse(event.getEventLoc().c_str());
403  if (eventLoc == nullptr)
404  {
405  eventLoc = cJSON_CreateObject();
406  }
407  cJSON_AddItemToObject(singleEvent, "Location", eventLoc);
408  // Event description
409  cJSON *eventDescription = cJSON_CreateString(
410  event.getEventDescription().c_str());
411  cJSON_AddItemToObject(singleEvent, "Description", eventDescription);
412 
413  cJSON_AddItemToArray(eventList, singleEvent);
414  }
415  }
416  cJSON_AddItemToObject(singleDefect, "Events", eventList);
417 
419  char *singleDefectStr = cJSON_Print(singleDefect);
420  jsonFile << singleDefectStr;
421  if (commaCounter != 0)
422  {
423  jsonFile << ",\n";
424  }
425  commaCounter--;
426 
428  cJSON_Delete(singleDefect);
429  }
430  jsonFile << "\n],\n";
431 
433  jsonFile << "\"Time\": " << time << ",\n";
434  jsonFile << "\"Memory\": \"" << mem << "\",\n";
435  jsonFile << "\"Coverage\": " << coverage << "\n";
436 
437  jsonFile << "}";
438  jsonFile.close();
439 }
#define BRANCHFLAGMASK
Definition: SVFBugReport.h:40
cJSON_Delete(null)
const char *const string
Definition: cJSON.h:172
std::vector< SVFBugEvent > EventStack
Definition: SVFBugReport.h:83
virtual const std::string getEventLoc() const
virtual const std::string getFuncName() const
const std::string & getName() const
Definition: SVFValue.h:243
std::string bugMsg1(const std::string &msg)
Definition: SVFUtil.cpp:81
std::ostream & errs()
Overwrite llvm::errs()
Definition: SVFUtil.h:56
std::string bugMsg2(const std::string &msg)
Definition: SVFUtil.cpp:86
for isBitcode
Definition: BasicTypes.h:68
llvm::Loop Loop
LLVM Loop.
Definition: BasicTypes.h:140
Definition: cJSON.h:104