SVF
TypeBasedHeapCloning.cpp
Go to the documentation of this file.
1 //===- TypeBasedHeapCloning.cpp -- Type filter/type-based heap cloning base ------------//
2 
3 /*
4  * TypeBasedHeapCloning.cpp
5  *
6  * Created on: Feb 08, 2020
7  * Author: Mohamad Barbar
8  */
9 
10 #include "SVF-FE/CPPUtil.h"
13 
14 using namespace SVF;
15 
17 
18 const std::string TypeBasedHeapCloning::derefFnName = "deref";
19 const std::string TypeBasedHeapCloning::mangledDerefFnName = "_Z5derefv";
20 
22 {
23  this->pta = pta;
24 }
25 
27 {
28  this->dchg = dchg;
29 }
30 
32 {
33  ppag = pag;
34 }
35 
37 {
38  if (isClone(o)) o = cloneToOriginalObj.at(o);
39  return SVFUtil::isa<ObjPN>(ppag->getPAGNode(o)) && ppag->isBlkObjOrConstantObj(o);
40 }
41 
42 bool TypeBasedHeapCloning::isBase(const DIType *a, const DIType *b) const
43 {
44  assert(dchg && "TBHC: DCHG not set!");
45  return dchg->isBase(a, b, true);
46 }
47 
49 {
50  return cloneToOriginalObj.find(o) != cloneToOriginalObj.end();
51 }
52 
54 {
55  objToType.insert({o, t});
56 }
57 
59 {
60  assert(objToType.find(o) != objToType.end() && "TBHC: object has no type?");
61  return objToType.at(o);
62 }
63 
65 {
66  objToAllocation.insert({o, site});
67 }
68 
70 {
71  assert(objToAllocation.find(o) != objToAllocation.end() && "TBHC: object has no allocation site?");
72  return objToAllocation.at(o);
73 }
74 
76 {
77  NodeBS objs;
78  for (std::pair<NodeID, NodeBS> oc : objToClones)
79  {
80  objs.set(oc.first);
81  }
82 
83  return objs;
84 }
85 
87 {
88  objToClones[o].set(c);
89 }
90 
92 {
93  return objToClones[o];
94 }
95 
97 {
98  cloneToOriginalObj.insert({c, o});
99 }
100 
102 {
103  if (isClone(c))
104  {
106  && "TBHC: original object not set for clone?");
107  return cloneToOriginalObj.at(c);
108  }
109 
110  return c;
111 }
112 
114 {
115  return locToFilterSet[loc];
116 }
117 
118 void TypeBasedHeapCloning::addGepToObj(NodeID gep, NodeID base, unsigned offset)
119 {
120  objToGeps[base].set(gep);
121  const PAGNode *baseNode = ppag->getPAGNode(base);
122  assert(baseNode && "TBHC: given bad base node?");
123  const ObjPN *baseObj = SVFUtil::dyn_cast<ObjPN>(baseNode);
124  assert(baseObj && "TBHC: non-object given for base?");
125  // We can use the base or the gep mem. obj.; should be identical.
126  const MemObj *baseMemObj = baseObj->getMemObj();
127 
128  objToGeps[base].set(gep);
129  memObjToGeps[baseMemObj][offset].set(gep);
130 }
131 
132 const NodeBS &TypeBasedHeapCloning::getGepObjsFromMemObj(const MemObj *memObj, unsigned offset)
133 {
134  return memObjToGeps[memObj][offset];
135 }
136 
138 {
139  return objToGeps[base];
140 }
141 
143 {
144  assert(dchg && "TBHC: DCHG not set!");
145  // Set of GEP objects we will return.
146  NodeBS geps;
147 
148  PAGNode *node = ppag->getPAGNode(base);
149  assert(node && "TBHC: base object node does not exist.");
150  ObjPN *baseNode = SVFUtil::dyn_cast<ObjPN>(node);
151  assert(baseNode && "TBHC: base \"object\" node is not an object.");
152 
153  // totalOffset is the offset from the real base (i.e. base of base),
154  // offset is the offset into base, whether it is a field itself or not.
155  unsigned totalOffset = offset;
156  if (const GepObjPN *baseGep = SVFUtil::dyn_cast<GepObjPN>(baseNode))
157  {
158  totalOffset += baseGep->getLocationSet().getOffset();
159  }
160 
161  const DIType *baseType = getType(base);
162 
163  // First field? Just return the whole object; same thing.
164  // For arrays, we want things to work as normal because an array *object* is more
165  // like a pointer than a struct object.
166  if (offset == 0 && baseType->getTag() != dwarf::DW_TAG_array_type)
167  {
168  // The base object is the 0 gep object.
169  addGepToObj(base, base, 0);
170  geps.set(base);
171  return geps;
172  }
173 
174  if (baseNode->getMemObj()->isFieldInsensitive())
175  {
176  // If it's field-insensitive, the base represents everything.
177  geps.set(base);
178  return geps;
179  }
180 
181  // Caching on offset would improve performance but it seems minimal.
182  const NodeBS &gepObjs = getGepObjs(base);
183  for (NodeID gep : gepObjs)
184  {
185  PAGNode *node = ppag->getPAGNode(gep);
186  assert(node && "TBHC: expected gep node doesn't exist.");
187  assert((SVFUtil::isa<GepObjPN>(node) || SVFUtil::isa<FIObjPN>(node))
188  && "TBHC: expected a GEP or FI object.");
189 
190  if (GepObjPN *gepNode = SVFUtil::dyn_cast<GepObjPN>(node))
191  {
192  if (gepNode->getLocationSet().getOffset() == totalOffset)
193  {
194  geps.set(gep);
195  }
196  }
197  else
198  {
199  // Definitely a FIObj (asserted), but we don't want to add it if
200  // the object is field-sensitive because in that case it actually
201  // represents the 0th field, not the whole object.
202  if (baseNode->getMemObj()->isFieldInsensitive())
203  {
204  geps.set(gep);
205  }
206  }
207  }
208 
209  if (geps.empty())
210  {
211  // No gep node has even be created, so create one.
212  NodeID newGep;
213  LocationSet newLS;
214  // fldIdx is what is returned by getOffset.
215  newLS.setFldIdx(totalOffset);
216 
217  if (isClone(base))
218  {
219  // Don't use ppag->getGepObjNode because base and it's original object
220  // have the same memory object which is the key PAG uses.
221  newGep = addCloneGepObjNode(baseNode->getMemObj(), newLS);
222  }
223  else
224  {
225  newGep = ppag->getGepObjNode(base, newLS);
226  }
227 
228  if (GepObjPN *gep = SVFUtil::dyn_cast<GepObjPN>(ppag->getPAGNode(newGep)))
229  {
230  gep->setBaseNode(base);
231  }
232 
233  addGepToObj(newGep, base, totalOffset);
234  const DIType *newGepType = nullptr;
235  if (baseType->getTag() == dwarf::DW_TAG_array_type || baseType->getTag() == dwarf::DW_TAG_pointer_type)
236  {
237  if (const DICompositeType *arrayType = SVFUtil::dyn_cast<DICompositeType>(baseType))
238  {
239  // Array access.
240  newGepType = arrayType->getBaseType();
241  }
242  else if (const DIDerivedType *ptrType = SVFUtil::dyn_cast<DIDerivedType>(baseType))
243  {
244  // Pointer access.
245  newGepType = ptrType->getBaseType();
246  }
247  assert(newGepType && "TBHC: newGepType is neither DIComposite nor DIDerived");
248 
249  // Get the canonical type because we got the type from the DIType infrastructure directly.
250  newGepType = dchg->getCanonicalType(newGepType);
251  }
252  else
253  {
254  // Must be a struct/class.
255  // Don't use totalOffset because we're operating on the Gep object which is our parent
256  // (i.e. field of some base, not the base itself).
257  newGepType = dchg->getFieldType(getType(base), offset);
258  }
259 
260  setType(newGep, newGepType);
261  // We call the object created in the non-TBHC analysis the original object.
262  setOriginalObj(newGep, ppag->getGepObjNode(baseNode->getMemObj(), offset));
263  setAllocationSite(newGep, 0);
264 
265  geps.set(newGep);
266  }
267 
268  return geps;
269 }
270 
271 bool TypeBasedHeapCloning::init(NodeID loc, NodeID p, const DIType *tildet, bool reuse, bool gep)
272 {
273  assert(dchg && "TBHC: DCHG not set!");
274  bool changed = false;
275 
276  const PointsTo &pPt = pta->getPts(p);
277  // The points-to set we will populate in the loop to fill pPt.
278  PointsTo pNewPt;
279 
280  PointsTo &filterSet = getFilterSet(loc);
281  for (NodeID o : pPt)
282  {
283  // If it's been filtered before, it'll be filtered again.
284  if (filterSet.test(o)) continue;
285 
286  PAGNode *obj = ppag->getPAGNode(o);
287  assert(obj && "TBHC: pointee object does not exist in PAG?");
288  const DIType *tp = getType(o); // tp is t'
289 
290  // When an object is field-insensitive, we can't filter on any of the fields' types.
291  // i.e. a pointer of the field type can safely access an object of the base/struct
292  // type if that object is field-insensitive.
293  bool fieldInsensitive = false;
294  std::vector<const DIType *> fieldTypes;
295  if (ObjPN *obj = SVFUtil::dyn_cast<ObjPN>(ppag->getPAGNode(o)))
296  {
297  fieldInsensitive = obj->getMemObj()->isFieldInsensitive();
298  if (tp != nullptr && (tp->getTag() == dwarf::DW_TAG_structure_type
299  || tp->getTag() == dwarf::DW_TAG_class_type))
300  {
301  fieldTypes = dchg->getFieldTypes(tp);
302  }
303  }
304 
305  const Set<const DIType *> &aggs = dchg->isAgg(tp)
306  ? dchg->getAggs(tp) : Set<const DIType *>();
307 
308  NodeID prop;
309  bool filter = false;
310  if (tp == undefType)
311  {
312  // o is uninitialised.
313  // GEP objects should never be uninitialised; type assigned at creation.
314  assert(!isGep(obj) && "TBHC: GEP object is untyped!");
315  prop = cloneObject(o, tildet, false);
316  ++numInit;
317  if (!pta->isHeapMemObj(o) && !SVFUtil::isa<DummyObjPN>(obj)) ++numSGInit;
318  }
319  else if (fieldInsensitive && tp && dchg->isFieldOf(tildet, tp))
320  {
321  // Field-insensitive object but the instruction is operating on a field.
322  prop = o;
323  ++numTBWU;
324  if (!pta->isHeapMemObj(o) && !SVFUtil::isa<DummyObjPN>(obj)) ++numSGTBWU;
325  }
326  else if (gep && aggs.find(tildet) != aggs.end())
327  {
328  // SVF treats two consecutive GEPs as children to the same load/store.
329  // Special case for aggregates.
330  // SVF will transform (for example)
331  // `1: s = get struct element X from array a; 2: f = get field of struct Y from s;`
332  // to `1: s = get struct element X from array a; 2: f = get field of struct Y from a;`
333  // so we want the second instruction to be operating on an object of type
334  // 'Struct S', not 'Array of S'.
335  prop = cloneObject(o, tildet, false);
336  ++numAgg;
337  if (!pta->isHeapMemObj(o) && !SVFUtil::isa<DummyObjPN>(obj)) ++numSGAgg;
338  }
339  else if (isBase(tp, tildet) && tp != tildet
340  && (reuse || dchg->isFirstField(tp, tildet) || (!reuse && pta->isHeapMemObj(o))))
341  {
342  // Downcast.
343  // One of three conditions:
344  // - !reuse && heap: because downcasts should not happen to stack/globals.
345  // - isFirstField because ^ can happen because when we take the field of a
346  // struct that is a struct, we get its first field, then it may downcast
347  // back to the struct at another GEP.
348  // TODO: this can probably be solved more cleanly.
349  // - reuse: because it can happen to stack/heap objects.
350  prop = cloneObject(o, tildet, reuse);
351  ++numTBSSU;
352  if (!pta->isHeapMemObj(o) && !SVFUtil::isa<DummyObjPN>(obj)) ++numSGTBSSU;
353  }
354  else if (isBase(tildet, tp))
355  {
356  // Upcast.
357  prop = o;
358  ++numTBWU;
359  if (!pta->isHeapMemObj(o) && !SVFUtil::isa<DummyObjPN>(obj)) ++numSGTBWU;
360  }
361  else if (tildet != tp && reuse)
362  {
363  // Reuse.
364  prop = cloneObject(o, tildet, true);
365  ++numReuse;
366  if (!pta->isHeapMemObj(o) && !SVFUtil::isa<DummyObjPN>(obj)) ++numSGReuse;
367  }
368  else
369  {
370  // Some spurious objects will be filtered.
371  filter = true;
372  prop = o;
373  ++numTBSU;
374  if (!pta->isHeapMemObj(o) && !SVFUtil::isa<DummyObjPN>(obj)) ++numSGTBSU;
375  }
376 
377  if (prop != o)
378  {
379  // If we cloned, we want to keep o in p's PTS but filter it (ignore it later).
380  pNewPt.set(o);
381  filterSet.set(o);
382  // TODO: hack, sound but imprecise and unclean.
383  // In the aggs case there is a difference between it being good for
384  // arrays and structs. For now, just propagate both the clone and the original
385  // object till a cleaner solution is found.
386  if (gep && aggs.find(tildet) != aggs.end())
387  {
388  filterSet.reset(o);
389  }
390  }
391 
392  pNewPt.set(prop);
393 
394  if (filter)
395  {
396  filterSet.set(o);
397  }
398  }
399 
400  if (pPt != pNewPt)
401  {
402  // Seems fast enough to perform in the naive way.
403  pta->clearFullPts(p);
404  pta->unionPts(p, pNewPt);
405  changed = true;
406  }
407 
408  return changed;
409 }
410 
412 {
413  NodeID clone;
414  const PAGNode *obj = ppag->getPAGNode(o);
415  if (const GepObjPN *gepObj = SVFUtil::dyn_cast<GepObjPN>(obj))
416  {
417  const NodeBS &clones = getGepObjClones(gepObj->getBaseNode(), gepObj->getLocationSet().getOffset());
418  // TODO: a bit of repetition.
419  for (NodeID clone : clones)
420  {
421  if (getType(clone) == type)
422  {
423  return clone;
424  }
425  }
426 
427  clone = addCloneGepObjNode(gepObj->getMemObj(), gepObj->getLocationSet());
428 
429  // The base needs to know about the new clone.
430  addGepToObj(clone, gepObj->getBaseNode(), gepObj->getLocationSet().getOffset());
431 
432  addClone(o, clone);
433  addClone(getOriginalObj(o), clone);
434  // The only instance of original object of a Gep object being retrieved is for
435  // IN sets and gepToSVFGRetriever in FSTBHC, so we don't care that clone comes
436  // from o (we can get that by checking the base and offset).
437  setOriginalObj(clone, getOriginalObj(o));
439  cloneGepObj->setBaseNode(gepObj->getBaseNode());
440  }
441  else if (SVFUtil::isa<FIObjPN>(obj) || SVFUtil::isa<DummyObjPN>(obj))
442  {
443  o = getOriginalObj(o);
444  // Check there isn't an appropriate clone already.
445  const NodeBS &clones = getClones(o);
446  for (NodeID clone : clones)
447  {
448  if (getType(clone) == type)
449  {
450  return clone;
451  }
452  }
453 
454  if (const FIObjPN *fiObj = SVFUtil::dyn_cast<FIObjPN>(obj))
455  {
456  clone = addCloneFIObjNode(fiObj->getMemObj());
457  }
458  else
459  {
460  const DummyObjPN *dummyObj = SVFUtil::dyn_cast<DummyObjPN>(obj);
461  clone = addCloneDummyObjNode(dummyObj->getMemObj());
462  }
463  // We checked above that it's an FIObj or a DummyObj.
464 
465  // Tracking object<->clone mappings.
466  addClone(o, clone);
467  setOriginalObj(clone, o);
468  }
469  else
470  {
471  assert(false && "FSTBHC: trying to clone unhandled object");
472  }
473 
474  // Clone's metadata. This can be shared between Geps/otherwise.
475  setType(clone, type);
477 
478  backPropagate(clone);
479 
480  return clone;
481 }
482 
484 {
485  assert(v != nullptr && "TBHC: trying to get metadata from nullptr!");
486 
487  const MDNode *mdNode = nullptr;
488  if (const Instruction *inst = SVFUtil::dyn_cast<Instruction>(v))
489  {
490  mdNode = inst->getMetadata(cppUtil::ctir::derefMDName);
491  }
492  else if (const GlobalObject *go = SVFUtil::dyn_cast<GlobalObject>(v))
493  {
494  mdNode = go->getMetadata(cppUtil::ctir::derefMDName);
495  }
496 
497  // Will be nullptr if metadata isn't there.
498  return mdNode;
499 }
500 
502 {
504  return ppag->addObjNode(nullptr, new CloneDummyObjPN(id, mem), id);
505 }
506 
508 {
510  return ppag->addObjNode(mem->getRefVal(), new CloneGepObjPN(mem, id, l), id);
511 }
512 
514 {
516  return ppag->addObjNode(mem->getRefVal(), new CloneFIObjPN(mem->getRefVal(), id, mem), id);
517 }
518 
520 {
521  assert(v != nullptr && "TBHC: trying to get type from nullptr!");
522 
523  const MDNode *mdNode = getRawCTirMetadata(v);
524  if (mdNode == nullptr)
525  {
526  return nullptr;
527  }
528 
529  const DIType *type = SVFUtil::dyn_cast<DIType>(mdNode);
530  if (type == nullptr)
531  {
532  SVFUtil::errs() << "TBHC: bad ctir metadata type\n";
533  return nullptr;
534  }
535 
536  return dchg->getCanonicalType(type);
537 }
538 
540 {
541  assert(n != nullptr && "TBHC: testing if null is a GEP object!");
542  return SVFUtil::isa<GepObjPN>(n);
543 }
544 
546 static bool isAliasTestFunction(std::string name)
547 {
560 }
561 
563 {
564  const LLVMModuleSet *llvmModuleSet = LLVMModuleSet::getLLVMModuleSet();
565  for (u32_t i = 0; i < llvmModuleSet->getModuleNum(); ++i)
566  {
567  const PAG::CallSiteSet &callSites = ppag->getCallSiteSet();
568  for (const CallBlockNode *cbn : callSites)
569  {
570  const CallSite &cs = SVFUtil::getLLVMCallSite(cbn->getCallSite());
571  const Function *fn = cs.getCalledFunction();
572  if (fn == nullptr || !isAliasTestFunction(fn->getName().str()))
573  {
574  continue;
575  }
576 
577  // We have a test call,
578  // We want the store which stores to the pointer in question (i.e. operand of the
579  // store is the pointer, and the store itself is the dereference).
580  const StoreInst *ps = nullptr, *qs = nullptr;
581  // Check: currInst is a deref call, so p/q is prevInst.
582 
583  // Find p.
584  const Instruction *prevInst = nullptr;
585  const Instruction *currInst = cs.getInstruction();
586  do
587  {
588  if (const CallInst *ci = SVFUtil::dyn_cast<CallInst>(currInst))
589  {
590  std::string calledFnName = ci->getCalledFunction()->getName().str();
591  if (calledFnName == derefFnName || calledFnName == mangledDerefFnName)
592  {
593  const StoreInst *si = SVFUtil::dyn_cast<StoreInst>(prevInst);
594  assert(si && "TBHC: validation macro not producing stores?");
595  ps = si;
596  break;
597  }
598  }
599 
600  prevInst = currInst;
601  currInst = currInst->getNextNonDebugInstruction();
602  }
603  while (currInst != nullptr);
604 
605  // Repeat for q.
606  while (currInst != nullptr)
607  {
608  // while loop, not do-while, because we need to the next instruction (current
609  // instruction is the first deref()).
610  prevInst = currInst;
611  currInst = currInst->getNextNonDebugInstruction();
612 
613  if (const CallInst *ci = SVFUtil::dyn_cast<CallInst>(currInst))
614  {
615  std::string calledFnName = ci->getCalledFunction()->getName().str();
616  if (calledFnName == derefFnName || calledFnName == mangledDerefFnName)
617  {
618  const StoreInst *si = SVFUtil::dyn_cast<StoreInst>(prevInst);
619  assert(si && "TBHC: validation macro not producing stores?");
620  qs = si;
621  break;
622  }
623  }
624  }
625 
626  assert(ps != nullptr && qs != nullptr && "TBHC: malformed alias test?");
627  NodeID p = ppag->getValueNode(ps->getPointerOperand()),
628  q = ppag->getValueNode(qs->getPointerOperand());
629  const DIType *pt = getTypeFromCTirMetadata(ps), *qt = getTypeFromCTirMetadata(qs);
630 
631  // Now filter both points-to sets according to the type of the value.
632  const PointsTo &pPts = pta->getPts(p), &qPts = pta->getPts(q);
633  PointsTo pPtsFiltered, qPtsFiltered;
634  for (NodeID o : pPts)
635  {
636  if (getType(o) != undefType && isBase(pt, getType(o)))
637  {
638  pPtsFiltered.set(o);
639  }
640  }
641 
642  for (NodeID o : qPts)
643  {
644  if (getType(o) != undefType && isBase(qt, getType(o)))
645  {
646  qPtsFiltered.set(o);
647  }
648  }
649 
651  assert(bvpta && "TBHC: need a BVDataPTAImpl for TBHC alias testing.");
652  AliasResult res = bvpta->alias(pPtsFiltered, qPtsFiltered);
653 
654  bool passed = false;
655  std::string testName = "";
656  if (fn->getName() == PointerAnalysis::aliasTestMayAlias
657  || fn->getName() == PointerAnalysis::aliasTestMayAliasMangled)
658  {
659  passed = res == llvm::MayAlias || res == llvm::MustAlias;
661  }
662  else if (fn->getName() == PointerAnalysis::aliasTestNoAlias
663  || fn->getName() == PointerAnalysis::aliasTestNoAliasMangled)
664  {
665  passed = res == llvm::NoAlias;
667  }
668  else if (fn->getName() == PointerAnalysis::aliasTestMustAlias
669  || fn->getName() == PointerAnalysis::aliasTestMustAliasMangled)
670  {
671  passed = res == llvm::MustAlias || res == llvm::MayAlias;
673  }
674  else if (fn->getName() == PointerAnalysis::aliasTestPartialAlias
676  {
677  passed = res == llvm::MayAlias || res == llvm::PartialAlias;
679  }
680  else if (fn->getName() == PointerAnalysis::aliasTestFailMayAlias
682  {
683  passed = res != llvm::MayAlias && res != llvm::MustAlias && res != llvm::PartialAlias;
685  }
686  else if (fn->getName() == PointerAnalysis::aliasTestFailNoAlias
688  {
689  passed = res != llvm::NoAlias;
691  }
692 
693  SVFUtil::outs() << "[" << pta->PTAName() << "] Checking " << testName << "\n";
694  raw_ostream &msgStream = passed ? SVFUtil::outs() : SVFUtil::errs();
695  msgStream << (passed ? SVFUtil::sucMsg("\t SUCCESS") : SVFUtil::errMsg("\t FAILURE"))
696  << " : " << testName
697  << " check <id:" << p << ", id:" << q << "> "
698  << "at (" << SVFUtil::getSourceLoc(cs.getInstruction()) << ")\n";
699  if (!passed)
700  assert(false && "test case failed!");
701 
702  if (pPtsFiltered.empty())
703  {
704  msgStream << SVFUtil::wrnMsg("\t WARNING")
705  << " : pts(" << p << ") is empty\n";
706  }
707 
708  if (qPtsFiltered.empty())
709  {
710  msgStream << SVFUtil::wrnMsg("\t WARNING")
711  << " : pts(" << q << ") is empty\n";
712  }
713 
714  if (testName == PointerAnalysis::aliasTestMustAlias)
715  {
716  msgStream << SVFUtil::wrnMsg("\t WARNING")
717  << " : MUSTALIAS tests are actually MAYALIAS tests\n";
718  }
719 
721  {
722  msgStream << SVFUtil::wrnMsg("\t WARNING")
723  << " : PARTIALALIAS tests are actually MAYALIAS tests\n";
724  }
725 
726  msgStream.flush();
727  }
728  }
729 }
730 
732 {
733  std::string indent = "";
734  SVFUtil::outs() << "@@@@@@@@@ TBHC STATISTICS @@@@@@@@@\n";
735  indent = " ";
736 
737  // Print clones with their types.
738  SVFUtil::outs() << indent << "=== Original objects to clones ===\n";
739  indent = " ";
740  unsigned totalClones = 0;
741  const NodeBS objs = getObjsWithClones();
742  for (NodeID o : objs)
743  {
744  const NodeBS &clones = getClones(o);
745  if (clones.count() == 0) continue;
746 
747  totalClones += clones.count();
748  SVFUtil::outs() << indent
749  << " " << o << " : "
750  << "(" << clones.count() << ")"
751  << "[ ";
752  bool first = true;
753  for (NodeID c : clones)
754  {
755  if (!first)
756  {
757  SVFUtil::outs() << ", ";
758  }
759 
760  SVFUtil::outs() << c
761  << "{"
762  << dchg->diTypeToStr(getType(c))
763  << "}";
764  first = false;
765  }
766 
767  SVFUtil::outs() << " ]\n";
768  }
769 
770  indent = " ";
771  SVFUtil::outs() << indent
772  << "Total: " << ppag->getObjectNodeNum() + ppag->getFieldObjNodeNum() + totalClones
773  << " (" << totalClones << " clones)\n";
774  SVFUtil::outs() << indent << "==================================\n";
775 
776  SVFUtil::outs() << indent << "INITIALISE : " << numInit << "\n";
777  SVFUtil::outs() << indent << "TBWU : " << numTBWU << "\n";
778  SVFUtil::outs() << indent << "TBSSU : " << numTBSSU << "\n";
779  SVFUtil::outs() << indent << "TBSU : " << numTBSU << "\n";
780  SVFUtil::outs() << indent << "REUSE : " << numReuse << "\n";
781  SVFUtil::outs() << indent << "AGG CASE : " << numAgg << "\n";
782 
783  SVFUtil::outs() << "\n";
784  SVFUtil::outs() << indent << "STACK/GLOBAL OBJECTS\n";
785  indent = " ";
786  SVFUtil::outs() << indent << "INITIALISE : " << numSGInit << "\n";
787  SVFUtil::outs() << indent << "TBWU : " << numSGTBWU << "\n";
788  SVFUtil::outs() << indent << "TBSSU : " << numSGTBSSU << "\n";
789  SVFUtil::outs() << indent << "TBSU : " << numSGTBSU << "\n";
790  SVFUtil::outs() << indent << "REUSE : " << numSGReuse << "\n";
791  SVFUtil::outs() << indent << "AGG CASE : " << numSGAgg << "\n";
792 
793  SVFUtil::outs() << "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n";
794 }
void setOriginalObj(NodeID c, NodeID o)
static bool isAliasTestFunction(std::string name)
Returns true if the function name matches MAYALIAS, NOALIAS, etc.
static std::string diTypeToStr(const DIType *)
Returns a human-readable version of the DIType.
Definition: DCHG.cpp:958
const std::vector< const DIType * > & getFieldTypes(const DIType *base)
Returns a vector of the types of all fields in base.
Definition: DCHG.h:327
virtual void clearFullPts(NodeID id)
Clear points-to set of id.
llvm::StoreInst StoreInst
Definition: BasicTypes.h:146
NodeID getValueNode(const Value *V)
Get PAG Node according to LLVM value.
Definition: PAG.h:521
virtual void backPropagate(NodeID clone)=0
static const std::string derefFnName
deref function for TBHC alias tests.
bool isBlkObjOrConstantObj(NodeID id) const
Definition: PAG.h:613
const MemObj * getMemObj() const
Return memory object.
Definition: PAGNode.h:359
llvm::raw_ostream raw_ostream
LLVM outputs.
Definition: BasicTypes.h:99
u32_t NodeID
Definition: SVFBasicTypes.h:80
static const std::string aliasTestFailMayAliasMangled
TypeBasedHeapCloning(BVDataPTAImpl *pta)
Constructor. pta is the pointer analysis using this object (i.e. that which is extending).
static const std::string aliasTestNoAlias
const NodeBS & getGepObjs(NodeID base)
Map< NodeID, const DIType * > objToType
Object -> its type.
void setBaseNode(NodeID base)
Set the base object from which this GEP node came from.
Definition: PAGNode.h:497
#define assert(ex)
Definition: util.h:141
Map< NodeID, PointsTo > locToFilterSet
Maps nodes (a location like a PAG node or SVFG node) to their filter set.
raw_ostream & errs()
Overwrite llvm::errs()
Definition: SVFUtil.h:53
void setType(NodeID o, const DIType *t)
Sets the type (in objToType) of o.
Map< NodeID, NodeBS > objToGeps
Maps objects to the GEP nodes beneath them.
NodeID addCloneFIObjNode(const MemObj *mem)
Add clone FI object node to PAG.
bool isBlkObjOrConstantObj(NodeID o) const
llvm::CallInst CallInst
Definition: BasicTypes.h:143
void setFldIdx(Size_t idx)
Definition: LocationSet.h:202
NodeID addObjNode(const Value *val, NodeID i)
Add a memory obj node.
Definition: PAG.h:707
bool isFieldInsensitive() const
Return true if its field limit is 0.
Definition: MemModel.h:337
NodeID addCloneGepObjNode(const MemObj *mem, const LocationSet &l)
Add clone GEP object node to PAG.
CallBase * getInstruction() const
Definition: BasicTypes.h:316
Definition: PAG.h:47
std::string getSourceLoc(const Value *val)
Return source code including line number and file name from debug information.
Definition: SVFUtil.cpp:259
Dwarf based CHG.
Definition: DCHG.h:208
virtual bool unionPts(NodeID id, const PointsTo &target)
llvm::DICompositeType DICompositeType
Definition: BasicTypes.h:219
NodeID allocateObjectId(void)
Allocate an object ID as determined by the strategy.
Size_t getFieldObjNodeNum() const
Definition: PAG.h:434
std::string sucMsg(std::string msg)
Returns successful message by converting a string into green string output.
Definition: SVFUtil.cpp:54
static std::string indent(size_t n)
Definition: DCHG.cpp:1126
llvm::GlobalObject GlobalObject
Definition: BasicTypes.h:81
const Set< const DIType * > & getAggs(const DIType *base)
Returns all the aggregates contained (transitively) in base.
Definition: DCHG.h:343
u32_t getModuleNum() const
Definition: LLVMModule.h:91
unsigned u32_t
Definition: SVFBasicTypes.h:75
static const DIType * undefType
The undefined type (•); void.
const std::string derefMDName
Definition: CPPUtil.h:113
BVDataPTAImpl * pta
PTA extending this class.
Map< NodeID, NodeID > objToAllocation
PAG * ppag
PAG the PTA uses. Just a shortcut for getPAG().
static bool isAgg(const DIType *t)
Definition: DCHG.cpp:342
PAGNode * getPAGNode(NodeID id) const
Get PAGNode ID.
Definition: PAG.h:513
static const std::string aliasTestMayAliasMangled
const NodeBS getObjsWithClones(void)
Returns objects that have clones (any key in objToClones).
static const std::string aliasTestFailNoAlias
void setPAG(PAG *pag)
PAG must be set by extending class once the PAG is available.
const Value * getRefVal() const
Get the reference value to this object.
Definition: MemModel.h:325
std::unordered_set< Key, Hash, KeyEqual, Allocator > Set
Definition: SVFBasicTypes.h:93
llvm::Function Function
Definition: BasicTypes.h:76
virtual const PointsTo & getPts(NodeID id)
llvm::Instruction Instruction
Definition: BasicTypes.h:79
NodeID getGepObjNode(const MemObj *obj, const LocationSet &ls)
Get a field PAG Object node according to base mem obj and offset.
Definition: PAG.cpp:671
llvm::DIDerivedType DIDerivedType
Definition: BasicTypes.h:220
virtual bool isFieldOf(const DIType *f, const DIType *b)
Returns true if f is a field of b (fields from getFieldTypes).
Definition: DCHG.cpp:677
static const std::string mangledDerefFnName
deref function (mangled) for TBHC alias tests.
NodeID cloneObject(NodeID o, const DIType *type, bool reuse)
void setDCHG(DCHGraph *dchg)
DCHG must be set by extending class once the DCHG is available.
void dumpStats(void)
Dump some statistics we tracked.
void validateTBHCTests(SVFModule *svfMod)
static const std::string aliasTestMustAliasMangled
static const std::string aliasTestNoAliasMangled
Set< const CallBlockNode * > CallSiteSet
Definition: PAG.h:51
Size_t getObjectNodeNum() const
Definition: PAG.h:426
static const std::string aliasTestMayAlias
const NodeBS & getGepObjsFromMemObj(const MemObj *memObj, unsigned offset)
static const std::string aliasTestMustAlias
NodeID getAllocationSite(NodeID o) const
Returns the allocation site (from objToAllocation) of o. Asserts existence.
static const MDNode * getRawCTirMetadata(const Value *)
Returns raw ctir metadata of a Value. Returns null if it doesn&#39;t exist.
raw_ostream & outs()
Overwrite llvm::outs()
Definition: SVFUtil.h:47
static const std::string aliasTestPartialAlias
bool isBase(const DIType *a, const DIType *b) const
const DIType * getType(NodeID o) const
Returns the type (from objToType) of o. Asserts existence.
bool isHeapMemObj(NodeID id) const
Whether this object is heap or array.
Function * getCalledFunction() const
Definition: BasicTypes.h:326
void setAllocationSite(NodeID o, NodeID site)
Sets the allocation site (in objToAllocation) of o.
const DIType * getFieldType(const DIType *base, unsigned idx)
Returns the type of field number idx (flattened) in base.
Definition: DCHG.h:291
const DIType * getCanonicalType(const DIType *t)
Definition: DCHG.cpp:713
llvm::MDNode MDNode
Definition: BasicTypes.h:138
virtual bool isBase(const DIType *a, const DIType *b, bool firstField)
Definition: DCHG.cpp:666
static LLVMModuleSet * getLLVMModuleSet()
Definition: LLVMModule.h:69
CallSite getLLVMCallSite(const Instruction *inst)
Return LLVM callsite given a instruction.
Definition: SVFUtil.h:183
static const std::string aliasTestFailNoAliasMangled
Map< NodeID, NodeID > cloneToOriginalObj
(Clone) object -> original object (opposite of objToclones).
for isBitcode
Definition: ContextDDA.h:15
static NodeIDAllocator * get(void)
Return (singleton) allocator.
bool isClone(NodeID o) const
Returns true if o is a clone.
llvm::SparseBitVector NodeBS
Definition: SVFBasicTypes.h:87
const NodeBS & getClones(NodeID o)
Returns all the clones of o.
PointsTo & getFilterSet(NodeID loc)
Returns the filter set of a location. Not const; could create empty PointsTo.
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Definition: Casting.h:343
bool isGep(const PAGNode *n) const
Test whether object is a GEP object. For convenience.
NodeID addCloneDummyObjNode(const MemObj *mem)
Add clone dummy object node to PAG.
const DIType * getTypeFromCTirMetadata(const Value *)
static const std::string aliasTestPartialAliasMangled
Map< NodeID, NodeBS > objToClones
(Original) object -> set of its clones.
std::string wrnMsg(std::string msg)
Returns warning message by converting a string into yellow string output.
Definition: SVFUtil.cpp:62
const NodeBS getGepObjClones(NodeID base, unsigned offset)
Map< const MemObj *, Map< unsigned, NodeBS > > memObjToGeps
Maps memory objects to their GEP objects. (memobj -> (fieldidx -> geps))
void addClone(NodeID o, NodeID c)
Add a clone c to object o.
bool init(NodeID loc, NodeID p, const DIType *tildet, bool reuse, bool gep=false)
std::string errMsg(std::string msg)
Print error message by converting a string into red string output.
Definition: SVFUtil.cpp:76
bool isFirstField(const DIType *f, const DIType *b)
Definition: DCHG.cpp:931
virtual const std::string PTAName() const
Return PTA name.
const CallSiteSet & getCallSiteSet() const
Definition: PAG.h:201
NodeID getOriginalObj(NodeID c) const
Returns the original object c is cloned from. If c is not a clone, returns itself.
static const std::string aliasTestFailMayAlias
llvm::Value Value
Definition: BasicTypes.h:78
NodeBS PointsTo
Definition: SVFBasicTypes.h:88
virtual AliasResult alias(const MemoryLocation &LocA, const MemoryLocation &LocB)
Interface expose to users of our pointer analysis, given Location infos.
llvm::DIType DIType
Definition: BasicTypes.h:217
void addGepToObj(NodeID gep, NodeID base, unsigned offset)
Associates gep with base (through objToGeps and memObjToGeps).
llvm::AliasResult AliasResult
Definition: BasicTypes.h:130