Static Value-Flow Analysis
ContextDDA.cpp
Go to the documentation of this file.
1 //===- ContextDDA.cpp -- Context-sensitive demand-driven analysis-------------//
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  * ContextDDA.cpp
25  *
26  * Created on: Aug 17, 2014
27  * Author: Yulei Sui
28  */
29 
30 #include "Util/Options.h"
31 #include "DDA/ContextDDA.h"
32 #include "DDA/FlowDDA.h"
33 #include "DDA/DDAClient.h"
34 #include "MemoryModel/PointsTo.h"
35 
36 using namespace SVF;
37 using namespace SVFUtil;
38 
44  _client(client)
45 {
46  flowDDA = new FlowDDA(_pag, client);
47 }
48 
53 {
54  if(flowDDA)
55  delete flowDDA;
56  flowDDA = nullptr;
57 }
58 
63 {
65  buildSVFG(pag);
68  stat = setDDAStat(new DDAStat(this));
70 }
71 
76 {
77 
78  resetQuery();
80 
81  NodeID id = var.get_id();
82  PAGNode* node = getPAG()->getGNode(id);
83  CxtLocDPItem dpm = getDPIm(var, getDefSVFGNode(node));
84 
85  // start DDA analysis
86  DOTIMESTAT(double start = DDAStat::getClk(true));
87  const CxtPtSet& cpts = findPT(dpm);
90 
91  if(isOutOfBudgetQuery() == false)
92  unionPts(var,cpts);
93  else
95 
96  if (this->printStat())
99  return this->getPts(var);
100 }
101 
106 {
107  ContextCond cxt;
108  CxtVar var(cxt, id);
109  computeDDAPts(var);
110 }
111 
116 {
117 
118  DBOUT(DGENERAL,outs() << "~~~Out of budget query, downgrade to flow sensitive analysis \n");
120  const PointsTo& flowPts = flowDDA->getPts(dpm.getCurNodeID());
121  CxtPtSet cxtPts;
122  for(PointsTo::iterator it = flowPts.begin(), eit = flowPts.end(); it!=eit; ++it)
123  {
124  ContextCond cxt;
125  CxtVar var(cxt, *it);
126  cxtPts.set(var);
127  }
128  updateCachedPointsTo(dpm,cxtPts);
129  unionPts(dpm.getCondVar(),cxtPts);
130  addOutOfBudgetDpm(dpm);
131 }
132 
136 bool ContextDDA::isCondCompatible(const ContextCond& cxt1, const ContextCond& cxt2, bool singleton) const
137 {
138  if(singleton)
139  return true;
140 
141  int i = cxt1.cxtSize() - 1;
142  int j = cxt2.cxtSize() - 1;
143  for(; i >= 0 && j>=0; i--, j--)
144  {
145  if(cxt1[i] != cxt2[j])
146  return false;
147  }
148  return true;
149 }
150 
155 {
156  CxtPtSet tmpDstPts;
157  for (CxtPtSet::iterator piter = srcPts.begin(); piter != srcPts.end(); ++piter)
158  {
159 
160  CxtVar ptd = *piter;
161  if (isBlkObjOrConstantObj(ptd.get_id()))
162  tmpDstPts.set(ptd);
163  else
164  {
165  const GepStmt* gepStmt = SVFUtil::cast<GepStmt>(gep->getPAGEdge());
166  if (gepStmt->isVariantFieldGep())
167  {
169  CxtVar var(ptd.get_cond(),getFIObjVar(ptd.get_id()));
170  tmpDstPts.set(var);
171  }
172  else
173  {
174  CxtVar var(ptd.get_cond(),getGepObjVar(ptd.get_id(),
175  gepStmt->getAccessPath().getConstantStructFldIdx()));
176  tmpDstPts.set(var);
177  }
178  }
179  }
180 
181  DBOUT(DDDA, outs() << "\t return created gep objs ");
182  DBOUT(DDDA, outs() << srcPts.toString());
183  DBOUT(DDDA, outs() << " --> ");
184  DBOUT(DDDA, outs() << tmpDstPts.toString());
185  DBOUT(DDDA, outs() << "\n");
186  return tmpDstPts;
187 }
188 
190 {
191  if(getPAG()->isIndirectCallSites(cs))
192  {
193  NodeID id = getPAG()->getFunPtr(cs);
194  PAGNode* node = getPAG()->getGNode(id);
195  CxtVar funptrVar(dpm.getCondVar().get_cond(), id);
196  CxtLocDPItem funptrDpm = getDPIm(funptrVar,getDefSVFGNode(node));
197  PointsTo pts = getBVPointsTo(findPT(funptrDpm));
198  if(pts.test(getPAG()->getObjectNode(callee)))
199  return true;
200  else
201  return false;
202  }
203  return true;
204 }
205 
211 {
212 
213  CallSiteID svfg_csId = 0;
214  if (const CallDirSVFGEdge* callEdge = SVFUtil::dyn_cast<CallDirSVFGEdge>(edge))
215  svfg_csId = callEdge->getCallSiteId();
216  else
217  svfg_csId = SVFUtil::cast<CallIndSVFGEdge>(edge)->getCallSiteId();
218 
219  const CallICFGNode* cbn = getSVFG()->getCallSite(svfg_csId);
220  const SVFFunction* callee = edge->getDstNode()->getFun();
221 
222  if(getCallGraph()->hasCallSiteID(cbn,callee))
223  {
224  return getCallGraph()->getCallSiteID(cbn,callee);
225  }
226 
227  return 0;
228 }
229 
235 {
236 
237  CallSiteID svfg_csId = 0;
238  if (const RetDirSVFGEdge* retEdge = SVFUtil::dyn_cast<RetDirSVFGEdge>(edge))
239  svfg_csId = retEdge->getCallSiteId();
240  else
241  svfg_csId = SVFUtil::cast<RetIndSVFGEdge>(edge)->getCallSiteId();
242 
243  const CallICFGNode* cbn = getSVFG()->getCallSite(svfg_csId);
244  const SVFFunction* callee = edge->getSrcNode()->getFun();
245 
246  if(getCallGraph()->hasCallSiteID(cbn,callee))
247  {
248  return getCallGraph()->getCallSiteID(cbn,callee);
249  }
250 
251  return 0;
252 }
253 
254 
257 {
259 
260  if (edge->isCallVFGEdge())
261  {
263  if(CallSiteID csId = getCSIDAtCall(dpm,edge))
264  {
265 
266  if(isEdgeInRecursion(csId))
267  {
268  DBOUT(DDDA,outs() << "\t\t call edge " << getCallGraph()->getCallerOfCallSite(csId)->getName() <<
269  "=>" << getCallGraph()->getCalleeOfCallSite(csId)->getName() << "in recursion \n");
271  }
272  else
273  {
274  if (dpm.matchContext(csId) == false)
275  {
276  DBOUT(DDDA, outs() << "\t\t context not match, edge "
277  << edge->getDstID() << " --| " << edge->getSrcID() << " \t");
278  DBOUT(DDDA, dumpContexts(dpm.getCond()));
279  return false;
280  }
281 
282  DBOUT(DDDA, outs() << "\t\t match contexts ");
283  DBOUT(DDDA, dumpContexts(dpm.getCond()));
284  }
285  }
286  }
287 
288  else if (edge->isRetVFGEdge())
289  {
291  if(CallSiteID csId = getCSIDAtRet(dpm,edge))
292  {
293 
294  if(isEdgeInRecursion(csId))
295  {
296  DBOUT(DDDA,outs() << "\t\t return edge " << getCallGraph()->getCalleeOfCallSite(csId)->getName() <<
297  "=>" << getCallGraph()->getCallerOfCallSite(csId)->getName() << "in recursion \n");
299  }
300  else
301  {
304  if (dpm.getCond().containCallStr(csId))
305  {
306  outOfBudgetQuery = true;
307  SVFUtil::writeWrnMsg("Call site ID is contained in call string. Is this a recursion?");
308  return false;
309  }
310  else
311  {
312  assert(dpm.getCond().containCallStr(csId) ==false && "contain visited call string ??");
313  if(dpm.pushContext(csId))
314  {
315  DBOUT(DDDA, outs() << "\t\t push context ");
316  DBOUT(DDDA, dumpContexts(dpm.getCond()));
317  }
318  else
319  {
320  DBOUT(DDDA, outs() << "\t\t context is full ");
321  DBOUT(DDDA, dumpContexts(dpm.getCond()));
322  }
323  }
324  }
325  }
326  }
327 
328  return true;
329 }
330 
331 
336 {
337  const MemObj* mem = _pag->getObject(getPtrNodeID(var));
338  assert(mem && "memory object is null??");
339  if (mem->isHeap())
340  {
341  if (!mem->getValue())
342  {
343  PAGNode *pnode = _pag->getGNode(getPtrNodeID(var));
344  GepObjVar* gepobj = SVFUtil::dyn_cast<GepObjVar>(pnode);
345  if (gepobj != nullptr)
346  {
347  assert(SVFUtil::isa<DummyObjVar>(_pag->getGNode(gepobj->getBaseNode()))
348  && "empty refVal in a gep object whose base is a non-dummy object");
349  }
350  else
351  {
352  assert((SVFUtil::isa<DummyObjVar, DummyValVar>(pnode))
353  && "empty refVal in non-dummy object");
354  }
355  return true;
356  }
357  else if(const SVFBaseNode* gNode = mem->getGNode())
358  {
359  if (const auto& node =
360  SVFUtil::dyn_cast<ICFGNode>(gNode))
361  {
362  const SVFFunction* svfFun = node->getFun();
363  if(_ander->isInRecursion(svfFun))
364  return true;
365  if(var.get_cond().isConcreteCxt() == false)
366  return true;
367  if(_pag->getICFG()->isInLoop(node))
368  return true;
369  }
370  }
371  }
372  return false;
373 }
#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
#define DDDA
Definition: SVFType.h:496
#define DOSTAT(X)
Definition: SVFType.h:485
#define DOTIMESTAT(X)
Definition: SVFType.h:486
APOffset getConstantStructFldIdx() const
Get methods.
Definition: AccessPath.h:100
const PointsTo & getPts(NodeID id) override
virtual bool unionPts(CVar id, const CPtSet &target)
virtual const CPtSet & getPts(CVar id)
virtual PointsTo getBVPointsTo(const CPtSet &cpts) const
Given a conditional pts return its bit vector points-to.
std::string toString() const
OrderedSet< Element >::iterator iterator
iterator end()
iterator begin()
Iterators.
void set(const Element &var)
Add the element into set.
NodeID get_id() const
const Cond & get_cond() const
u32_t cxtSize() const
Get context size.
Definition: DPItem.h:260
bool containCallStr(NodeID cxt) const
Whether contains callstring cxt.
Definition: DPItem.h:255
virtual bool isHeapCondMemObj(const CxtVar &var, const StoreSVFGNode *store) override
Definition: ContextDDA.cpp:335
bool testIndCallReachability(CxtLocDPItem &dpm, const SVFFunction *callee, const CallICFGNode *cs)
refine indirect call edge
Definition: ContextDDA.cpp:189
void handleOutOfBudgetDpm(const CxtLocDPItem &dpm)
Handle out-of-budget dpm.
Definition: ContextDDA.cpp:115
virtual void popRecursiveCallSites(CxtLocDPItem &dpm)
Pop recursive callsites.
Definition: ContextDDA.h:123
FlowDDA * flowDDA
downgrade to flowDDA if out-of-budget
Definition: ContextDDA.h:224
CallSiteID getCSIDAtCall(CxtLocDPItem &dpm, const SVFGEdge *edge)
get callsite id from call, return 0 if it is a spurious call edge
Definition: ContextDDA.cpp:210
virtual void computeDDAPts(NodeID id) override
Compute points-to set for an unconditional pointer.
Definition: ContextDDA.cpp:105
virtual bool isEdgeInRecursion(CallSiteID csId)
Whether call/return inside recursion.
Definition: ContextDDA.h:134
virtual bool isCondCompatible(const ContextCond &cxt1, const ContextCond &cxt2, bool singleton) const override
Definition: ContextDDA.cpp:136
virtual ~ContextDDA()
Destructor.
Definition: ContextDDA.cpp:52
virtual NodeID getPtrNodeID(const CxtVar &var) const override
Override parent method.
Definition: ContextDDA.h:100
CallSiteID getCSIDAtRet(CxtLocDPItem &dpm, const SVFGEdge *edge)
get callsite id from return, return 0 if it is a spurious return edge
Definition: ContextDDA.cpp:234
virtual bool handleBKCondition(CxtLocDPItem &dpm, const SVFGEdge *edge) override
Handle condition for context or path analysis (backward analysis)
Definition: ContextDDA.cpp:256
virtual void dumpContexts(const ContextCond &cxts)
dump context call strings
Definition: ContextDDA.h:212
ContextDDA(SVFIR *_pag, DDAClient *client)
Constructor.
Definition: ContextDDA.cpp:42
virtual void initialize() override
Initialization of the analysis.
Definition: ContextDDA.cpp:62
DDAClient * _client
DDA client.
Definition: ContextDDA.h:225
virtual CxtPtSet processGepPts(const GepSVFGNode *gep, const CxtPtSet &srcPts) override
processGep node
Definition: ContextDDA.cpp:154
bool matchContext(NodeID cxt)
Match context.
Definition: DPItem.h:430
bool pushContext(NodeID cxt)
Push context.
Definition: DPItem.h:424
CxtVar getCondVar() const
Get context var.
Definition: DPItem.h:408
const ContextCond & getCond() const
Get context.
Definition: DPItem.h:414
virtual void handleStatement(const SVFGNode *, NodeID)
Call back used by DDAVFSolver.
Definition: DDAClient.h:77
double _AnaTimePerQuery
Definition: DDAStat.h:61
double _TotalTimeOfQueries
Definition: DDAStat.h:63
virtual void updateCachedPointsTo(const CxtLocDPItem &dpm, const CxtPtSet &pts)
Definition: DDAVFSolver.h:563
virtual const CxtPtSet & findPT(const CxtLocDPItem &dpm)
Compute points-to.
Definition: DDAVFSolver.h:138
const SVFGNode * getDefSVFGNode(const PAGNode *pagNode) const
GetDefinition SVFG.
Definition: DDAVFSolver.h:347
AndersenWaveDiff * _ander
Andersen's analysis.
Definition: DDAVFSolver.h:776
void setCallGraphSCC(CallGraphSCC *scc)
Set callgraphSCC.
Definition: DDAVFSolver.h:632
virtual CxtLocDPItem getDPIm(const CxtVar &var, const SVFGNode *loc) const
Given CVar and location (SVFGNode) return a new DPItem.
Definition: DDAVFSolver.h:96
DDAStat * setDDAStat(DDAStat *s)
Set DDAStat.
Definition: DDAVFSolver.h:747
void addOutOfBudgetDpm(const CxtLocDPItem &dpm)
Definition: DDAVFSolver.h:736
virtual void buildSVFG(SVFIR *pag)
Build SVFG.
Definition: DDAVFSolver.h:317
void setCallGraph(PTACallGraph *cg)
Set callgraph.
Definition: DDAVFSolver.h:627
bool outOfBudgetQuery
Whether the current query is out of step limits.
Definition: DDAVFSolver.h:773
virtual void resetQuery()
Reset visited map for next points-to query.
Definition: DDAVFSolver.h:324
NodeID getCurNodeID() const
Definition: DPItem.h:77
static void setMaxBudget(u32_t max)
set max step budge per query
Definition: DPItem.h:86
void computeDDAPts(NodeID id) override
Compute points-to set for all top variable.
Definition: FlowDDA.cpp:43
virtual void initialize() override
Initialization of the analysis.
Definition: FlowDDA.h:86
NodeType * getSrcNode() const
Definition: GenericGraph.h:97
NodeID getDstID() const
Definition: GenericGraph.h:85
NodeID getSrcID() const
get methods of the components
Definition: GenericGraph.h:81
NodeType * getDstNode() const
Definition: GenericGraph.h:101
NodeType * getGNode(NodeID id) const
Get a node.
Definition: GenericGraph.h:653
NodeID getBaseNode(void) const
Return the base object from which this GEP node came from.
Definition: SVFVariables.h:512
bool isVariantFieldGep() const
Gep statement with a variant field index (pointer arithmetic) for struct field access.
const AccessPath & getAccessPath() const
bool isInLoop(const ICFGNode *node)
Whether node is in a loop.
Definition: ICFG.h:117
const SVFValue * getValue() const
Get the reference value to this object.
bool isHeap() const
const SVFBaseNode * getGNode() const
Get the reference value to this object.
static const Option< u32_t > CxtBudget
Definition: Options.h:81
CallSiteID getCallSiteID(const CallICFGNode *cs, const SVFFunction *callee) const
Definition: PTACallGraph.h:368
CallGraphSCC * getCallGraphSCC() const
Return call graph SCC.
SVFIR * getPAG() const
virtual void initialize()
Initialization of a pointer analysis, including building symbol table and SVFIR etc.
virtual bool isBlkObjOrConstantObj(NodeID ptd) const
bool printStat()
Whether print statistics.
PTAStat * stat
Statistics.
NodeID getFIObjVar(NodeID id)
PTACallGraph * getCallGraph() const
Return call graph.
bool isInRecursion(const SVFFunction *fun) const
NodeID getGepObjVar(NodeID id, const APOffset &ap)
void setObjFieldInsensitive(NodeID id)
static SVFIR * pag
SVFIR.
const_iterator end() const
Definition: PointsTo.h:132
const_iterator begin() const
Definition: PointsTo.h:128
bool test(u32_t n) const
Returns true if n is in this set.
Definition: PointsTo.cpp:131
NodeID getFunPtr(const CallICFGNode *cs) const
Definition: SVFIR.h:354
const MemObj * getObject(NodeID id) const
Definition: SVFIR.h:395
ICFG * getICFG() const
Definition: SVFIR.h:171
virtual void printStatPerQuery(NodeID, const PointsTo &)
Definition: SVFStat.h:89
virtual void performStatPerQuery(NodeID)
Definition: SVFStat.h:87
static double getClk(bool mark=false)
Definition: SVFStat.cpp:47
const PAGEdge * getPAGEdge() const
Definition: VFGNode.h:147
bool isRetVFGEdge() const
Definition: VFGEdge.h:88
bool isCallVFGEdge() const
Definition: VFGEdge.h:84
const CallICFGNode * getCallSite(CallSiteID id) const
Definition: VFG.h:182
void writeWrnMsg(const std::string &msg)
Writes a message run through wrnMsg.
Definition: SVFUtil.cpp:66
std::ostream & outs()
Overwrite llvm::outs()
Definition: SVFUtil.h:50
for isBitcode
Definition: BasicTypes.h:68
unsigned CallSiteID
Definition: GeneralType.h:58
u32_t NodeID
Definition: GeneralType.h:55