Static Value-Flow Analysis
Loading...
Searching...
No Matches
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
33using namespace SVF;
34using 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
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 {
62 SVFGNodeBS visited;
63 worklist.push(it->first->getCallICFGNode());
64 while (!worklist.empty())
65 {
66 const CallICFGNode* cs = worklist.pop();
69 const SVFGNode* node = getSVFG()->getDefSVFGNode(pagNode);
70 if (visited.test(node->getId()) == 0)
71 visited.set(node->getId());
72 else
73 continue;
74
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
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);
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()))
140 }
141 }
142 }
143 }
144 }
145 }
146}
147
149{
150
151 if(isAllPathReachable() == false && isSomePathReachable() == false)
152 {
153 // full leakage
155 {
157 };
159 }
160 else if (isAllPathReachable() == false && isSomePathReachable() == true)
161 {
162 // partial leakage
164 slice->evalFinalCond2Event(eventStack);
165 eventStack.push_back(
168 }
169
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
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 RetICFGNode * getRetICFGNode() const
Return callsite.
Definition ICFGNode.h:457
const std::string getSourceLoc() const override
Definition ICFGNode.h:588
const SVFFunction * getCalledFunction() const
Definition ICFGNode.h:518
std::vector< SVFBugEvent > EventStack
WorkList worklist
Worklist for resolution.
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)
void addSrcToCSID(const SVFGNode *src, const CallICFGNode *cs)
Record a source to its callsite.
virtual void initSrcs() override
Initialize sources and sinks.
virtual void initSnks() override
FIFOWorkList< const CallICFGNode * > CSWorkList
Definition LeakChecker.h:47
virtual bool isSinkLikeFun(const SVFFunction *fun) override
Whether the function is a heap deallocator (free/release memory)
Definition LeakChecker.h:86
virtual void reportBug(ProgSlice *slice) override
Report leaks.
void testsValidation(const ProgSlice *slice)
Validate test cases for regression test purpose.
const CallICFGNode * getSrcCSID(const SVFGNode *src)
void validateExpectedFailureTests(const SVFGNode *source, const SVFFunction *fun)
virtual bool isSourceLikeFun(const SVFFunction *fun) override
Whether the function is a heap allocator/reallocator (allocate memory)
Definition LeakChecker.h:81
static const Option< bool > ValidateTests
Definition Options.h:169
void getCallees(const CallICFGNode *cs, FunctionSet &callees)
Get all callees for a callsite.
Set< const SVFFunction * > FunctionSet
const CallICFGNode * getCallICFGNode() const
Definition ICFGNode.h:622
virtual const SVFType * getType() const
NodeID getId() const
Get ID.
const SVFFunction * getParent() const
Definition SVFValue.h:595
void addSaberBug(GenericBug::BugType bugType, const GenericBug::EventStack &eventStack)
bool isUncalledFunction() const
Definition SVFValue.h:466
const SVFGNode * getDefSVFGNode(const PAGNode *pagNode) const
Given a pagNode, return its definition site.
Definition SVFG.h:171
CSToArgsListMap & getCallSiteArgsMap()
Get callsite argument list.
Definition SVFIR.h:288
std::vector< const SVFVar * > SVFVarList
Definition SVFIR.h:60
CSToRetMap & getCallSiteRets()
Get callsite return.
Definition SVFIR.h:300
const SVFVar * getCallSiteRet(const RetICFGNode *cs) const
Get callsite return.
Definition SVFIR.h:305
GenericNode< SVFVar, SVFStmt >::GEdgeSetTy SVFStmtSetTy
bool isPointerTy() const
Definition SVFType.h:249
const std::string & getName() const
Definition SVFValue.h:243
bool test(unsigned Idx) const
void set(unsigned Idx)
virtual bool isSomePathReachable()
Whether it is some path reachable from a source.
Definition SrcSnkDDA.h:312
SVFIR * getPAG() const
Get SVFIR.
Definition SrcSnkDDA.h:120
Set< const CallICFGNode * > CallSiteSet
Definition SrcSnkDDA.h:64
PTACallGraph * getCallgraph() const
Get Callgraph.
Definition SrcSnkDDA.h:132
virtual bool isAllPathReachable()
Whether it is all path reachable from a source.
Definition SrcSnkDDA.h:307
void addToSinks(const SVFGNode *node)
Definition SrcSnkDDA.h:234
SVFBugReport report
Definition SrcSnkDDA.h:80
void addToSources(const SVFGNode *node)
Definition SrcSnkDDA.h:218
const SVFG * getSVFG() const
Get SVFG.
Definition SrcSnkDDA.h:126
bool isInAWrapper(const SVFGNode *src, CallSiteSet &csIdSet)
Identify allocation wrappers.
ActualParmVFGNode * getActualParmVFGNode(const PAGNode *aparm, const CallICFGNode *cs) const
Definition VFG.h:235
StmtVFGNode * getStmtVFGNode(const PAGEdge *pagEdge) const
Get an VFGNode.
Definition VFG.h:199
std::string sucMsg(const std::string &msg)
Returns successful message by converting a string into green string output.
Definition SVFUtil.cpp:54
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:77
std::ostream & errs()
Overwrite llvm::errs()
Definition SVFUtil.h:56
void writeWrnMsg(const std::string &msg)
Writes a message run through wrnMsg.
Definition SVFUtil.cpp:67
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:50
for isBitcode
Definition BasicTypes.h:68
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74