Static Value-Flow Analysis
Loading...
Searching...
No Matches
SaberSVFGBuilder.cpp
Go to the documentation of this file.
1//===- SaberSVFGBuilder.cpp -- SVFG builder in Saber-------------------------//
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 * SaberSVFGBuilder.cpp
25 *
26 * Created on: May 1, 2014
27 * Author: rockysui
28 */
29
33#include "Graphs/SVFG.h"
34#include "Util/Options.h"
36
37
38using namespace SVF;
39using namespace SVFUtil;
40
42{
43
44 MemSSA* mssa = svfg->getMSSA();
45 svfg->buildSVFG();
46 BVDataPTAImpl* pta = mssa->getPTA();
47 DBOUT(DGENERAL, outs() << pasMsg("\tCollect Global Variables\n"));
48
49 collectGlobals(pta);
50
51 DBOUT(DGENERAL, outs() << pasMsg("\tRemove Dereference Direct SVFG Edge\n"));
52
54
55 assert(saberCondAllocator && "saber condition allocator not set yet!");
57
58 DBOUT(DGENERAL, outs() << pasMsg("\tAdd Sink SVFG Nodes\n"));
59
61
62 if(pta->printStat())
63 svfg->performStat();
64}
65
66
71{
72 SVFIR* pag = svfg->getPAG();
73 NodeVector worklist;
74 for(SVFIR::iterator it = pag->begin(), eit = pag->end(); it!=eit; it++)
75 {
76 PAGNode* pagNode = it->second;
77 if (SVFUtil::isa<DummyValVar, DummyObjVar>(pagNode))
78 continue;
79
80 if(GepObjVar* gepobj = SVFUtil::dyn_cast<GepObjVar>(pagNode))
81 {
82 if(SVFUtil::isa<DummyObjVar>(pag->getGNode(gepobj->getBaseNode())))
83 continue;
84 }
85 if ((isa<ObjVar>(pagNode) && isa<GlobalObjVar>(pag->getBaseObject(pagNode->getId()))) ||
87 worklist.push_back(it->first);
88 }
89
91 while(!worklist.empty())
92 {
93 NodeID id = worklist.back();
94 worklist.pop_back();
95 globs.set(id);
96 const PointsTo& pts = pta->getPts(id);
97 for(PointsTo::iterator it = pts.begin(), eit = pts.end(); it!=eit; ++it)
98 {
100 }
101 }
102}
103
104
105/*
106 * https://github.com/SVF-tools/SVF/issues/991
107 *
108 * Originally, this function will collect all base pointers with all their fields
109 * inside the points-to set of global variables. But if a global variable points
110 * to the pointer returned by malloc() at some program points, then all pointers
111 * returned by malloc() will be included in the global set because of the
112 * context-insensitive pointer analysis results. This will make saber abandon
113 * too many slicing thus miss potential bugs.
114 *
115 * We add an option "saber-collect-extret-globals" to control whether this function
116 * will collect external functions' returned pointers. This option is true by default,
117 * making it to be false will let saber analyze more slicing but cause performance downgrade.
118 *
119 */
121{
122 SVFIR* pag = svfg->getPAG();
123
124 NodeID baseId = pag->getBaseObjVar(id);
125 NodeToPTSSMap::iterator it = cachedPtsMap.find(baseId);
126 if(it!=cachedPtsMap.end())
127 {
128 return it->second;
129 }
130 else
131 {
133 // base object
135 {
136 if(pta->isFIObjNode(baseId) && pag->getGNode(baseId)->hasValue())
137 {
138 ValVar* valVar = SVFUtil::dyn_cast<ValVar>(pag->getGNode(baseId));
139 if(valVar && valVar->getICFGNode() && SVFUtil::isExtCall(valVar->getICFGNode()))
140 {
141 return pts;
142 }
143 }
144 }
145
147
148 WorkList worklist;
149 for(PointsTo::iterator it = pts.begin(), eit = pts.end(); it!=eit; ++it)
150 worklist.push(*it);
151
152 while(!worklist.empty())
153 {
154 NodeID nodeId = worklist.pop();
155 const PointsTo& tmp = pta->getPts(nodeId);
156 for(PointsTo::iterator it = tmp.begin(), eit = tmp.end(); it!=eit; ++it)
157 {
159 }
160 }
161 return pts;
162 }
163}
164
169{
170
171 NodeID id = pagNode->getId();
172 PointsTo pts = pta->getPts(id);
173 pts.set(id);
174
175 return pts.intersects(globs);
176}
177
179{
180
181 for(SVFG::iterator it = svfg->begin(), eit = svfg->end(); it!=eit; ++it)
182 {
183 const SVFGNode* node = it->second;
184
185 if(const StmtSVFGNode* stmtNode = SVFUtil::dyn_cast<StmtSVFGNode>(node))
186 {
188 if(SVFUtil::isa<StoreSVFGNode>(stmtNode))
189 {
190 const SVFGNode* def = svfg->getDefSVFGNode(stmtNode->getPAGDstNode());
191 if(SVFGEdge* edge = svfg->getIntraVFGEdge(def,stmtNode,SVFGEdge::IntraDirectVF))
192 svfg->removeSVFGEdge(edge);
193 else
194 assert((svfg->getKind()==VFG::FULLSVFG_OPT || svfg->getKind()==VFG::PTRONLYSVFG_OPT) && "Edge not found!");
195
196 if(accessGlobal(pta,stmtNode->getPAGDstNode()))
197 {
198 globSVFGNodes.insert(stmtNode);
199 }
200 }
201 else if(SVFUtil::isa<LoadSVFGNode>(stmtNode))
202 {
203 const SVFGNode* def = svfg->getDefSVFGNode(stmtNode->getPAGSrcNode());
204 if(SVFGEdge* edge = svfg->getIntraVFGEdge(def,stmtNode,SVFGEdge::IntraDirectVF))
205 svfg->removeSVFGEdge(edge);
206 else
207 assert((svfg->getKind()==VFG::FULLSVFG_OPT || svfg->getKind()==VFG::PTRONLYSVFG_OPT) && "Edge not found!");
208
209 if(accessGlobal(pta,stmtNode->getPAGSrcNode()))
210 {
211 globSVFGNodes.insert(stmtNode);
212 }
213 }
214
215 }
216 }
217}
218
223{
224 bool isSU = false;
225 if (const StoreSVFGNode* store = SVFUtil::dyn_cast<StoreSVFGNode>(node))
226 {
227 const PointsTo& dstCPSet = pta->getPts(store->getPAGDstNodeID());
228 if (dstCPSet.count() == 1)
229 {
232 singleton = *it;
233
234 // Strong update can be made if this points-to target is not heap, array or field-insensitive.
235 if (!pta->isHeapMemObj(singleton) && !pta->isArrayMemObj(singleton)
238 {
239 isSU = true;
240 }
241 }
242 }
243 return isSU;
244}
245
257{
258
259 for(SVFG::iterator it = svfg->begin(), eit = svfg->end(); it!=eit; ++it)
260 {
261 const SVFGNode* node = it->second;
262
263 if(const StoreSVFGNode* stmtNode = SVFUtil::dyn_cast<StoreSVFGNode>(node))
264 {
265 if(SVFUtil::isa<StoreStmt>(stmtNode->getPAGEdge()))
266 {
268 if(isStrongUpdate(node, singleton, pta))
269 {
271 for (SVFGNode::const_iterator it2 = node->InEdgeBegin(), eit2 = node->InEdgeEnd(); it2 != eit2; ++it2)
272 {
273 if ((*it2)->isIndirectVFGEdge())
274 {
275 toRemove.insert(*it2);
276 }
277 }
278 for (SVFGEdge* edge: toRemove)
279 {
280 if (isa<StoreSVFGNode>(edge->getSrcNode()))
281 saberCondAllocator->getRemovedSUVFEdges()[edge->getSrcNode()].insert(edge->getDstNode());
282 svfg->removeSVFGEdge(edge);
283 }
284 }
285 }
286 }
287 }
288}
289
290
293{
294 SVFIR* pag = SVFIR::getPAG();
295 for(SVFIR::CSToArgsListMap::iterator it = pag->getCallSiteArgsMap().begin(),
296 eit = pag->getCallSiteArgsMap().end(); it!=eit; ++it)
297 {
299 callgraph->getCallees(it->first, callees);
300 for (PTACallGraph::FunctionSet::const_iterator cit = callees.begin(),
301 ecit = callees.end(); cit != ecit; cit++)
302 {
303
304 const SVFFunction* fun = *cit;
307 {
308 SVFIR::SVFVarList& arglist = it->second;
309 for(SVFIR::SVFVarList::const_iterator ait = arglist.begin(), aeit = arglist.end(); ait!=aeit; ++ait)
310 {
311 const PAGNode *pagNode = *ait;
312 if (pagNode->isPointer())
313 {
315 svfg->addIntraDirectVFEdge(svfg->getDefSVFGNode(pagNode)->getId(), svfg->getActualParmVFGNode(pagNode, it->first)->getId());
316 }
317 }
318 }
319 }
320 }
321}
#define DBOUT(TYPE, X)
LLVM debug macros, define type of your DBUG model of each pass.
Definition SVFType.h:484
#define DGENERAL
Definition SVFType.h:490
const PointsTo & getPts(NodeID id) override
bool push(const Data &data)
Definition WorkList.h:165
bool empty() const
Definition WorkList.h:146
iterator begin()
Iterators.
IDToNodeMapTy::iterator iterator
Node Iterators.
NodeType * getGNode(NodeID id) const
Get a node.
iterator InEdgeBegin()
iterator InEdgeEnd()
bool isFieldInsensitive() const
Return true if its field limit is 0.
BVDataPTAImpl * getPTA() const
Return PTA.
Definition MemSSA.h:308
static const Option< bool > CollectExtRetGlobals
Definition Options.h:202
void getCallees(const CallICFGNode *cs, FunctionSet &callees)
Get all callees for a callsite.
Set< const SVFFunction * > FunctionSet
bool isLocalVarInRecursiveFun(NodeID id) const
Whether a local variable is in function recursions.
bool printStat()
Whether print statistics.
bool isArrayMemObj(NodeID id) const
PTACallGraph * getCallGraph() const
Return call graph.
bool isHeapMemObj(NodeID id) const
Whether this object is heap or array.
bool isFIObjNode(NodeID id) const
void set(u32_t n)
Inserts n in the set.
Definition PointsTo.cpp:157
std::unique_ptr< SVFG > svfg
Definition SVFGBuilder.h:91
CSToArgsListMap & getCallSiteArgsMap()
Get callsite argument list.
Definition SVFIR.h:288
NodeBS getFieldsAfterCollapse(NodeID id)
Definition SVFIR.cpp:511
std::vector< const SVFVar * > SVFVarList
Definition SVFIR.h:60
const BaseObjVar * getBaseObject(NodeID id) const
Definition SVFIR.h:405
NodeID getBaseObjVar(NodeID id) const
Base and Offset methods for Value and Object node.
Definition SVFIR.h:477
const MemObj * getBaseObj(NodeID id) const
Definition SVFIR.h:481
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:116
const ValVar * getBaseValVar(NodeID id) const
Definition SVFIR.h:415
bool hasValue() const
bool isFClose(const SVFFunction *fun) const
Return true if this call is a file close.
bool isMemDealloc(const SVFFunction *fun) const
Return true if this call is a memory deallocation.
static SaberCheckerAPI * getCheckerAPI()
Return a static reference.
SVFGNodeToSVFGNodeSetMap & getRemovedSUVFEdges()
bool isStrongUpdate(const SVFGNode *node, NodeID &singleton, BVDataPTAImpl *pta)
Return TRUE if this is a strong update STORE statement.
void collectGlobals(BVDataPTAImpl *pta)
PointsTo & CollectPtsChain(BVDataPTAImpl *pta, NodeID id, NodeToPTSSMap &cachedPtsMap)
Collect objects along points-to chains.
bool accessGlobal(BVDataPTAImpl *pta, const PAGNode *pagNode)
Whether points-to of a PAGNode points-to global variable.
Map< NodeID, PointsTo > NodeToPTSSMap
virtual void buildSVFG()
Re-write create SVFG method.
SVFGNodeSet globSVFGNodes
Store all global SVFG nodes.
virtual void AddExtActualParmSVFGNodes(PTACallGraph *callgraph)
Add actual parameter SVFGNode for 1st argument of a deallocation like external function.
void addActualParmVFGNode(const PAGNode *pagNode, const CallICFGNode *cs)
Add ActualParmVFGNode.
SaberCondAllocator * saberCondAllocator
void rmDerefDirSVFGEdges(BVDataPTAImpl *pta)
virtual void rmIncomingEdgeForSUStore(BVDataPTAImpl *pta)
@ IntraDirectVF
Definition VFGEdge.h:53
VFGEdge::VFGEdgeSetTy::const_iterator const_iterator
Definition VFGNode.h:55
@ PTRONLYSVFG_OPT
Definition VFG.h:57
@ FULLSVFG_OPT
Definition VFG.h:57
bool isExtCall(const SVFFunction *fun)
Definition SVFUtil.h:278
std::string pasMsg(const std::string &msg)
Print each pass/phase message by converting a string into blue string output.
Definition SVFUtil.cpp:100
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:50
for isBitcode
Definition BasicTypes.h:68
std::vector< NodeID > NodeVector
u32_t NodeID
Definition GeneralType.h:55
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74