Static Value-Flow Analysis
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 
30 #include "SABER/SaberSVFGBuilder.h"
31 #include "SABER/SaberCheckerAPI.h"
33 #include "Graphs/SVFG.h"
34 #include "Util/Options.h"
36 
37 
38 using namespace SVF;
39 using 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 
53  rmDerefDirSVFGEdges(pta);
54 
55  assert(saberCondAllocator && "saber condition allocator not set yet!");
56  rmIncomingEdgeForSUStore(pta);
57 
58  DBOUT(DGENERAL, outs() << pasMsg("\tAdd Sink SVFG Nodes\n"));
59 
60  AddExtActualParmSVFGNodes(pta->getCallGraph());
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(const SVFValue* val = pagNode->getValue())
86  {
87  if(SVFUtil::isa<SVFGlobalValue>(val))
88  worklist.push_back(it->first);
89  }
90  }
91 
92  NodeToPTSSMap cachedPtsMap;
93  while(!worklist.empty())
94  {
95  NodeID id = worklist.back();
96  worklist.pop_back();
97  globs.set(id);
98  const PointsTo& pts = pta->getPts(id);
99  for(PointsTo::iterator it = pts.begin(), eit = pts.end(); it!=eit; ++it)
100  {
101  globs |= CollectPtsChain(pta,*it,cachedPtsMap);
102  }
103  }
104 }
105 
106 
107 /*
108  * https://github.com/SVF-tools/SVF/issues/991
109  *
110  * Originally, this function will collect all base pointers with all their fields
111  * inside the points-to set of global variables. But if a global variable points
112  * to the pointer returned by malloc() at some program points, then all pointers
113  * returned by malloc() will be included in the global set because of the
114  * context-insensitive pointer analysis results. This will make saber abandon
115  * too many slicing thus miss potential bugs.
116  *
117  * We add an option "saber-collect-extret-globals" to control whether this function
118  * will collect external functions' returned pointers. This option is true by default,
119  * making it to be false will let saber analyze more slicing but cause performance downgrade.
120  *
121  */
123 {
124  SVFIR* pag = svfg->getPAG();
125 
126  NodeID baseId = pag->getBaseObjVar(id);
127  NodeToPTSSMap::iterator it = cachedPtsMap.find(baseId);
128  if(it!=cachedPtsMap.end())
129  {
130  return it->second;
131  }
132  else
133  {
134  PointsTo& pts = cachedPtsMap[baseId];
135  // base object
137  {
138  if(pta->isFIObjNode(baseId) && pag->getGNode(baseId)->hasValue())
139  {
140  ValVar* valVar = SVFUtil::dyn_cast<ValVar>(pag->getGNode(baseId));
141  if(valVar && valVar->getGNode() && SVFUtil::isExtCall(SVFUtil::cast<ICFGNode>(valVar->getGNode())))
142  {
143  return pts;
144  }
145  }
146  }
147 
148  pts |= pag->getFieldsAfterCollapse(baseId);
149 
150  WorkList worklist;
151  for(PointsTo::iterator it = pts.begin(), eit = pts.end(); it!=eit; ++it)
152  worklist.push(*it);
153 
154  while(!worklist.empty())
155  {
156  NodeID nodeId = worklist.pop();
157  const PointsTo& tmp = pta->getPts(nodeId);
158  for(PointsTo::iterator it = tmp.begin(), eit = tmp.end(); it!=eit; ++it)
159  {
160  pts |= CollectPtsChain(pta,*it,cachedPtsMap);
161  }
162  }
163  return pts;
164  }
165 }
166 
171 {
172 
173  NodeID id = pagNode->getId();
174  PointsTo pts = pta->getPts(id);
175  pts.set(id);
176 
177  return pts.intersects(globs);
178 }
179 
181 {
182 
183  for(SVFG::iterator it = svfg->begin(), eit = svfg->end(); it!=eit; ++it)
184  {
185  const SVFGNode* node = it->second;
186 
187  if(const StmtSVFGNode* stmtNode = SVFUtil::dyn_cast<StmtSVFGNode>(node))
188  {
190  if(SVFUtil::isa<StoreSVFGNode>(stmtNode))
191  {
192  const SVFGNode* def = svfg->getDefSVFGNode(stmtNode->getPAGDstNode());
193  if(SVFGEdge* edge = svfg->getIntraVFGEdge(def,stmtNode,SVFGEdge::IntraDirectVF))
194  svfg->removeSVFGEdge(edge);
195  else
196  assert((svfg->getKind()==VFG::FULLSVFG_OPT || svfg->getKind()==VFG::PTRONLYSVFG_OPT) && "Edge not found!");
197 
198  if(accessGlobal(pta,stmtNode->getPAGDstNode()))
199  {
200  globSVFGNodes.insert(stmtNode);
201  }
202  }
203  else if(SVFUtil::isa<LoadSVFGNode>(stmtNode))
204  {
205  const SVFGNode* def = svfg->getDefSVFGNode(stmtNode->getPAGSrcNode());
206  if(SVFGEdge* edge = svfg->getIntraVFGEdge(def,stmtNode,SVFGEdge::IntraDirectVF))
207  svfg->removeSVFGEdge(edge);
208  else
209  assert((svfg->getKind()==VFG::FULLSVFG_OPT || svfg->getKind()==VFG::PTRONLYSVFG_OPT) && "Edge not found!");
210 
211  if(accessGlobal(pta,stmtNode->getPAGSrcNode()))
212  {
213  globSVFGNodes.insert(stmtNode);
214  }
215  }
216 
217  }
218  }
219 }
220 
225 {
226  bool isSU = false;
227  if (const StoreSVFGNode* store = SVFUtil::dyn_cast<StoreSVFGNode>(node))
228  {
229  const PointsTo& dstCPSet = pta->getPts(store->getPAGDstNodeID());
230  if (dstCPSet.count() == 1)
231  {
233  PointsTo::iterator it = dstCPSet.begin();
234  singleton = *it;
235 
236  // Strong update can be made if this points-to target is not heap, array or field-insensitive.
237  if (!pta->isHeapMemObj(singleton) && !pta->isArrayMemObj(singleton)
238  && SVFIR::getPAG()->getBaseObj(singleton)->isFieldInsensitive() == false
239  && !pta->isLocalVarInRecursiveFun(singleton))
240  {
241  isSU = true;
242  }
243  }
244  }
245  return isSU;
246 }
247 
259 {
260 
261  for(SVFG::iterator it = svfg->begin(), eit = svfg->end(); it!=eit; ++it)
262  {
263  const SVFGNode* node = it->second;
264 
265  if(const StoreSVFGNode* stmtNode = SVFUtil::dyn_cast<StoreSVFGNode>(node))
266  {
267  if(SVFUtil::isa<StoreStmt>(stmtNode->getPAGEdge()))
268  {
269  NodeID singleton;
270  if(isStrongUpdate(node, singleton, pta))
271  {
272  Set<SVFGEdge*> toRemove;
273  for (SVFGNode::const_iterator it2 = node->InEdgeBegin(), eit2 = node->InEdgeEnd(); it2 != eit2; ++it2)
274  {
275  if ((*it2)->isIndirectVFGEdge())
276  {
277  toRemove.insert(*it2);
278  }
279  }
280  for (SVFGEdge* edge: toRemove)
281  {
282  if (isa<StoreSVFGNode>(edge->getSrcNode()))
283  saberCondAllocator->getRemovedSUVFEdges()[edge->getSrcNode()].insert(edge->getDstNode());
284  svfg->removeSVFGEdge(edge);
285  }
286  }
287  }
288  }
289  }
290 }
291 
292 
295 {
296  SVFIR* pag = SVFIR::getPAG();
297  for(SVFIR::CSToArgsListMap::iterator it = pag->getCallSiteArgsMap().begin(),
298  eit = pag->getCallSiteArgsMap().end(); it!=eit; ++it)
299  {
301  callgraph->getCallees(it->first, callees);
302  for (PTACallGraph::FunctionSet::const_iterator cit = callees.begin(),
303  ecit = callees.end(); cit != ecit; cit++)
304  {
305 
306  const SVFFunction* fun = *cit;
307  if (SaberCheckerAPI::getCheckerAPI()->isMemDealloc(fun)
308  || SaberCheckerAPI::getCheckerAPI()->isFClose(fun))
309  {
310  SVFIR::SVFVarList& arglist = it->second;
311  for(SVFIR::SVFVarList::const_iterator ait = arglist.begin(), aeit = arglist.end(); ait!=aeit; ++ait)
312  {
313  const PAGNode *pagNode = *ait;
314  if (pagNode->isPointer())
315  {
316  addActualParmVFGNode(pagNode, it->first);
317  svfg->addIntraDirectVFEdge(svfg->getDefSVFGNode(pagNode)->getId(), svfg->getActualParmVFGNode(pagNode, it->first)->getId());
318  }
319  }
320  }
321  }
322  }
323 }
#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.
Definition: GenericGraph.h:627
NodeType * getGNode(NodeID id) const
Get a node.
Definition: GenericGraph.h:653
IDToNodeMapTy::iterator iterator
Node Iterators.
Definition: GenericGraph.h:606
iterator InEdgeBegin()
Definition: GenericGraph.h:462
iterator InEdgeEnd()
Definition: GenericGraph.h:466
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.
Definition: PTACallGraph.h:408
Set< const SVFFunction * > FunctionSet
Definition: PTACallGraph.h:251
bool isLocalVarInRecursiveFun(NodeID id) const
Whether a local variable is in function recursions.
bool printStat()
Whether print statistics.
PTACallGraph * getCallGraph() const
Return call graph.
bool isArrayMemObj(NodeID id) const
bool isHeapMemObj(NodeID id) const
Whether this object is heap or array.
bool isFIObjNode(NodeID id) const
const_iterator end() const
Definition: PointsTo.h:132
u32_t count() const
Returns number of elements.
Definition: PointsTo.cpp:111
void set(u32_t n)
Inserts n in the set.
Definition: PointsTo.cpp:157
const_iterator begin() const
Definition: PointsTo.h:128
bool intersects(const PointsTo &rhs) const
Returns true if this set and rhs share any elements.
Definition: PointsTo.cpp:189
NodeID getId() const
Get ID.
Definition: GenericGraph.h:260
CSToArgsListMap & getCallSiteArgsMap()
Get callsite argument list.
Definition: SVFIR.h:287
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition: SVFIR.h:115
NodeBS getFieldsAfterCollapse(NodeID id)
Definition: SVFIR.cpp:499
std::vector< const SVFVar * > SVFVarList
Definition: SVFIR.h:59
NodeID getBaseObjVar(NodeID id) const
Base and Offset methods for Value and Object node.
Definition: SVFIR.h:455
const MemObj * getBaseObj(NodeID id) const
Definition: SVFIR.h:459
bool hasValue() const
Definition: SVFVariables.h:101
virtual bool isPointer() const
Whether it is a pointer.
Definition: SVFVariables.h:106
const SVFValue * getValue() const
Get/has methods of the components.
Definition: SVFVariables.h:83
static SaberCheckerAPI * getCheckerAPI()
Return a static reference.
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.
virtual void AddExtActualParmSVFGNodes(PTACallGraph *callgraph)
Add actual parameter SVFGNode for 1st argument of a deallocation like external function.
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
const SVFBaseNode * getGNode() const
Definition: SVFVariables.h:311
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:99
std::ostream & outs()
Overwrite llvm::outs()
Definition: SVFUtil.h:50
for isBitcode
Definition: BasicTypes.h:68
std::vector< NodeID > NodeVector
Definition: GeneralType.h:116
u32_t NodeID
Definition: GeneralType.h:55
std::unordered_set< Key, Hash, KeyEqual, Allocator > Set
Definition: GeneralType.h:96