Static Value-Flow Analysis
LeakChecker.cpp
Go to the documentation of this file.
1 //===- LeakChecker.cpp -- Memory leak detector ------------------------------//
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  * LeakChecker.cpp
25  *
26  * Created on: Apr 2, 2014
27  * Author: Yulei Sui
28  */
29 
30 #include "Util/Options.h"
31 #include "SABER/LeakChecker.h"
32 
33 using namespace SVF;
34 using namespace SVFUtil;
35 
36 
41 {
42 
43  SVFIR* pag = getPAG();
44  for(SVFIR::CSToRetMap::iterator it = pag->getCallSiteRets().begin(),
45  eit = pag->getCallSiteRets().end(); it!=eit; ++it)
46  {
47  const RetICFGNode* cs = it->first;
51  if(cs->getFun()->isUncalledFunction() || !cs->getType()->isPointerTy())
52  continue;
53 
55  getCallgraph()->getCallees(cs->getCallICFGNode(),callees);
56  for(PTACallGraph::FunctionSet::const_iterator cit = callees.begin(), ecit = callees.end(); cit!=ecit; cit++)
57  {
58  const SVFFunction* fun = *cit;
59  if (isSourceLikeFun(fun))
60  {
61  CSWorkList worklist;
62  SVFGNodeBS visited;
63  worklist.push(it->first->getCallICFGNode());
64  while (!worklist.empty())
65  {
66  const CallICFGNode* cs = worklist.pop();
67  const RetICFGNode* retBlockNode = cs->getRetICFGNode();
68  const PAGNode* pagNode = pag->getCallSiteRet(retBlockNode);
69  const SVFGNode* node = getSVFG()->getDefSVFGNode(pagNode);
70  if (visited.test(node->getId()) == 0)
71  visited.set(node->getId());
72  else
73  continue;
74 
75  CallSiteSet csSet;
76  // if this node is in an allocation wrapper, find all its call nodes
77  if (isInAWrapper(node, csSet))
78  {
79  for (CallSiteSet::iterator it = csSet.begin(), eit =
80  csSet.end(); it != eit; ++it)
81  {
82  worklist.push(*it);
83  }
84  }
85  // otherwise, this is the source we are interested
86  else
87  {
88  // exclude sources in dead functions or sources in functions that have summary
89  if (!cs->getFun()->isUncalledFunction() && !isExtCall(cs->getBB()->getParent()))
90  {
91  addToSources(node);
92  addSrcToCSID(node, cs);
93  }
94  }
95  }
96  }
97  }
98  }
99 
100 }
101 
106 {
107 
108  SVFIR* pag = getPAG();
109 
110  for(SVFIR::CSToArgsListMap::iterator it = pag->getCallSiteArgsMap().begin(),
111  eit = pag->getCallSiteArgsMap().end(); it!=eit; ++it)
112  {
113 
115  getCallgraph()->getCallees(it->first,callees);
116  for(PTACallGraph::FunctionSet::const_iterator cit = callees.begin(), ecit = callees.end(); cit!=ecit; cit++)
117  {
118  const SVFFunction* fun = *cit;
119  if (isSinkLikeFun(fun))
120  {
121  SVFIR::SVFVarList &arglist = it->second;
122  assert(!arglist.empty() && "no actual parameter at deallocation site?");
124  for (SVFIR::SVFVarList::const_iterator ait = arglist.begin(),
125  aeit = arglist.end(); ait != aeit; ++ait)
126  {
127  const PAGNode *pagNode = *ait;
128  if (pagNode->isPointer())
129  {
130  const SVFGNode *snk = getSVFG()->getActualParmVFGNode(pagNode, it->first);
131  addToSinks(snk);
132 
133  // For any multi-level pointer e.g., XFree(void** pagNode) that passed into a ExtAPI::EFT_FREE_MULTILEVEL function (e.g., XFree),
134  // we will add the DstNode of a load edge, i.e., dummy = *pagNode
135  SVFStmt::SVFStmtSetTy& loads = const_cast<PAGNode*>(pagNode)->getOutgoingEdges(SVFStmt::Load);
136  for(const SVFStmt* ld : loads)
137  {
138  if(SVFUtil::isa<DummyValVar>(ld->getDstNode()))
139  addToSinks(getSVFG()->getStmtVFGNode(ld));
140  }
141  }
142  }
143  }
144  }
145  }
146 }
147 
149 {
150 
151  if(isAllPathReachable() == false && isSomePathReachable() == false)
152  {
153  // full leakage
154  GenericBug::EventStack eventStack =
155  {
156  SVFBugEvent(SVFBugEvent::SourceInst, getSrcCSID(slice->getSource()))
157  };
158  report.addSaberBug(GenericBug::NEVERFREE, eventStack);
159  }
160  else if (isAllPathReachable() == false && isSomePathReachable() == true)
161  {
162  // partial leakage
163  GenericBug::EventStack eventStack;
164  slice->evalFinalCond2Event(eventStack);
165  eventStack.push_back(
166  SVFBugEvent(SVFBugEvent::SourceInst, getSrcCSID(slice->getSource())));
167  report.addSaberBug(GenericBug::PARTIALLEAK, eventStack);
168  }
169 
171  testsValidation(slice);
172 }
173 
174 
179 {
180  const SVFGNode* source = slice->getSource();
181  const CallICFGNode* cs = getSrcCSID(source);
182  const SVFFunction* fun = cs->getCalledFunction();
183  if(fun==nullptr)
184  return;
185 
186  validateSuccessTests(source,fun);
187  validateExpectedFailureTests(source,fun);
188 }
189 
190 
192 {
193 
194  const CallICFGNode* cs = getSrcCSID(source);
195 
196  bool success = false;
197 
198  if(fun->getName() == "SAFEMALLOC")
199  {
200  if(isAllPathReachable() == true && isSomePathReachable() == true)
201  success = true;
202  }
203  else if(fun->getName() == "NFRMALLOC")
204  {
205  if(isAllPathReachable() == false && isSomePathReachable() == false)
206  success = true;
207  }
208  else if(fun->getName() == "PLKMALLOC")
209  {
210  if(isAllPathReachable() == false && isSomePathReachable() == true)
211  success = true;
212  }
213  else if(fun->getName() == "CLKMALLOC")
214  {
215  if(isAllPathReachable() == false && isSomePathReachable() == false)
216  success = true;
217  }
218  else if(fun->getName() == "NFRLEAKFP" || fun->getName() == "PLKLEAKFP"
219  || fun->getName() == "LEAKFN")
220  {
221  return;
222  }
223  else
224  {
225  writeWrnMsg("\t can not validate, check function not found, please put it at the right place!!");
226  return;
227  }
228 
229  std::string funName = source->getFun()->getName();
230 
231  if (success)
232  {
233  outs() << sucMsg("\t SUCCESS :") << funName << " check <src id:" << source->getId()
234  << ", cs id:" << (getSrcCSID(source))->valueOnlyToString() << "> at ("
235  << cs->getSourceLoc() << ")\n";
236  }
237  else
238  {
239  SVFUtil::errs() << errMsg("\t FAILURE :") << funName << " check <src id:" << source->getId()
240  << ", cs id:" << (getSrcCSID(source))->valueOnlyToString() << "> at ("
241  << cs->getSourceLoc() << ")\n";
242  assert(false && "test case failed!");
243  }
244 }
245 
247 {
248 
249  const CallICFGNode* cs = getSrcCSID(source);
250 
251  bool expectedFailure = false;
252 
253  if(fun->getName() == "NFRLEAKFP")
254  {
255  if(isAllPathReachable() == false && isSomePathReachable() == false)
256  expectedFailure = true;
257  }
258  else if(fun->getName() == "PLKLEAKFP")
259  {
260  if(isAllPathReachable() == false && isSomePathReachable() == true)
261  expectedFailure = true;
262  }
263  else if(fun->getName() == "LEAKFN")
264  {
265  if(isAllPathReachable() == true && isSomePathReachable() == true)
266  expectedFailure = true;
267  }
268  else if(fun->getName() == "SAFEMALLOC" || fun->getName() == "NFRMALLOC"
269  || fun->getName() == "PLKMALLOC" || fun->getName() == "CLKLEAKFN")
270  {
271  return;
272  }
273  else
274  {
275  writeWrnMsg("\t can not validate, check function not found, please put it at the right place!!");
276  return;
277  }
278 
279  std::string funName = source->getFun()->getName();
280 
281  if (expectedFailure)
282  {
283  outs() << sucMsg("\t EXPECTED-FAILURE :") << funName << " check <src id:" << source->getId()
284  << ", cs id:" << (getSrcCSID(source))->valueOnlyToString() << "> at ("
285  << cs->getSourceLoc() << ")\n";
286  }
287  else
288  {
289  SVFUtil::errs() << errMsg("\t UNEXPECTED FAILURE :") << funName
290  << " check <src id:" << source->getId()
291  << ", cs id:" << (getSrcCSID(source))->valueOnlyToString() << "> at ("
292  << cs->getSourceLoc() << ")\n";
293  assert(false && "test case failed!");
294  }
295 }
const char *const string
Definition: cJSON.h:172
const SVFFunction * getCalledFunction() const
Definition: ICFGNode.h:518
const std::string getSourceLoc() const override
Definition: ICFGNode.h:588
const RetICFGNode * getRetICFGNode() const
Return callsite.
Definition: ICFGNode.h:457
bool push(const Data &data)
Definition: WorkList.h:165
bool empty() const
Definition: WorkList.h:146
std::vector< SVFBugEvent > EventStack
Definition: SVFBugReport.h:83
virtual const SVFFunction * getFun() const
Return the function of this ICFGNode.
Definition: ICFGNode.h:76
virtual const SVFBasicBlock * getBB() const
Return the basic block of this ICFGNode.
Definition: ICFGNode.h:82
void validateSuccessTests(const SVFGNode *source, const SVFFunction *fun)
virtual void initSrcs() override
Initialize sources and sinks.
Definition: LeakChecker.cpp:40
virtual void initSnks() override
virtual void reportBug(ProgSlice *slice) override
Report leaks.
void testsValidation(const ProgSlice *slice)
Validate test cases for regression test purpose.
void validateExpectedFailureTests(const SVFGNode *source, const SVFFunction *fun)
static const Option< bool > ValidateTests
Definition: Options.h:169
Set< const SVFFunction * > FunctionSet
Definition: PTACallGraph.h:251
void evalFinalCond2Event(GenericBug::EventStack &eventStack) const
Add final condition to eventStack.
Definition: ProgSlice.cpp:196
const SVFGNode * getSource() const
root and sink operations
Definition: ProgSlice.h:123
const CallICFGNode * getCallICFGNode() const
Definition: ICFGNode.h:622
virtual const SVFType * getType() const
Definition: GenericGraph.h:271
NodeID getId() const
Get ID.
Definition: GenericGraph.h:260
const SVFFunction * getParent() const
Definition: SVFValue.h:584
bool isUncalledFunction() const
Definition: SVFValue.h:455
const SVFVar * getCallSiteRet(const RetICFGNode *cs) const
Get callsite return.
Definition: SVFIR.h:304
CSToArgsListMap & getCallSiteArgsMap()
Get callsite argument list.
Definition: SVFIR.h:287
std::vector< const SVFVar * > SVFVarList
Definition: SVFIR.h:59
CSToRetMap & getCallSiteRets()
Get callsite return.
Definition: SVFIR.h:299
GenericNode< SVFVar, SVFStmt >::GEdgeSetTy SVFStmtSetTy
bool isPointerTy() const
Definition: SVFType.h:249
const std::string & getName() const
Definition: SVFValue.h:243
virtual bool isPointer() const
Whether it is a pointer.
Definition: SVFVariables.h:106
bool test(unsigned Idx) const
void set(unsigned Idx)
Set< const CallICFGNode * > CallSiteSet
Definition: SrcSnkDDA.h:64
virtual const SVFFunction * getFun() const
Get the function of this SVFGNode.
Definition: VFGNode.h:79
std::string sucMsg(const std::string &msg)
Returns successful message by converting a string into green string output.
Definition: SVFUtil.cpp:53
bool isExtCall(const SVFFunction *fun)
Definition: SVFUtil.h:278
std::string errMsg(const std::string &msg)
Print error message by converting a string into red string output.
Definition: SVFUtil.cpp:76
void writeWrnMsg(const std::string &msg)
Writes a message run through wrnMsg.
Definition: SVFUtil.cpp:66
std::ostream & errs()
Overwrite llvm::errs()
Definition: SVFUtil.h:56
std::ostream & outs()
Overwrite llvm::outs()
Definition: SVFUtil.h:50
for isBitcode
Definition: BasicTypes.h:68