Static Value-Flow Analysis
Andersen.cpp
Go to the documentation of this file.
1 //===- Andersen.cpp -- Field-sensitive Andersen's analysis-------------------//
2 //
3 // SVF: Static Value-Flow Analysis
4 //
5 // Copyright (C) <2013-2017> <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  * Andersen.cpp
25  *
26  * Created on: Nov 12, 2013
27  * Author: Yulei Sui
28  */
29 
30 #include "Util/Options.h"
31 #include "Graphs/CHG.h"
32 #include "Util/SVFUtil.h"
33 #include "MemoryModel/PointsTo.h"
34 #include "WPA/Andersen.h"
35 #include "WPA/Steensgaard.h"
36 
37 using namespace SVF;
38 using namespace SVFUtil;
39 using namespace std;
40 
41 
49 
54 
60 
65 {
66  delete consCG;
67  consCG = nullptr;
68 }
69 
74 {
78  stat = new AndersenStat(this);
80  consCG = new ConstraintGraph(pag);
81  setGraph(consCG);
83  consCG->dump("consCG_initial");
84 }
85 
90 {
93  consCG->dump("consCG_final");
94 
96  consCG->print();
98 }
99 
101 {
102  // Start solving constraints
103  DBOUT(DGENERAL, outs() << SVFUtil::pasMsg("Start Solving Constraints\n"));
104 
106 
107  initWorklist();
108  do
109  {
110  numOfIteration++;
111  if (0 == numOfIteration % iterationForPrintStat)
112  printStat();
113 
114  reanalyze = false;
115 
116  solveWorklist();
117 
118  if (updateCallGraph(getIndirectCallsites()))
119  reanalyze = true;
120 
121  }
122  while (reanalyze);
123 
124  // Analysis is finished, reset the alarm if we set it.
125  SVFUtil::stopAnalysisLimitTimer(limitTimerSet);
126 
127  DBOUT(DGENERAL, outs() << SVFUtil::pasMsg("Finish Solving Constraints\n"));
128 }
129 
134 {
135  if(!Options::ReadAnder().empty())
136  {
137  readPtsFromFile(Options::ReadAnder());
138  }
139  else
140  {
141  if(Options::WriteAnder().empty())
142  {
143  initialize();
144  solveConstraints();
145  finalize();
146  }
147  else
148  {
149  solveAndwritePtsToFile(Options::WriteAnder());
150  }
151  }
152 }
153 
158 {
159  initialize();
160  if (!filename.empty())
161  this->readFromFile(filename);
162  finalize();
163 }
164 
169 {
171  initialize();
172  if (!filename.empty())
173  this->writeObjVarToFile(filename);
174  solveConstraints();
175  if (!filename.empty())
176  this->writeToFile(filename);
177  finalize();
178 }
179 
181 {
182  consCG->resetSubs(consCG->getRep(id));
183  for (NodeID sub: consCG->getSubs(id))
184  consCG->resetRep(sub);
185  consCG->resetSubs(id);
186  consCG->resetRep(id);
187  assert(!consCG->hasGNode(id) && "this is either a rep nodeid or a sub nodeid should have already been merged to its field-insensitive base! ");
188 }
189 
191 {
192 
193  double cgUpdateStart = stat->getClk();
194 
195  CallEdgeMap newEdges;
196  onTheFlyCallGraphSolve(callsites, newEdges);
197  NodePairSet cpySrcNodes;
198  for (CallEdgeMap::iterator it = newEdges.begin(), eit = newEdges.end();
199  it != eit; ++it)
200  {
201  for (FunctionSet::iterator cit = it->second.begin(),
202  ecit = it->second.end();
203  cit != ecit; ++cit)
204  {
205  connectCaller2CalleeParams(it->first, *cit, cpySrcNodes);
206  }
207  }
208 
209  bool hasNewForkEdges = updateThreadCallGraph(callsites, cpySrcNodes);
210 
211  for (NodePairSet::iterator it = cpySrcNodes.begin(),
212  eit = cpySrcNodes.end();
213  it != eit; ++it)
214  {
215  pushIntoWorklist(it->first);
216  }
217 
218  double cgUpdateEnd = stat->getClk();
219  timeOfUpdateCallGraph += (cgUpdateEnd - cgUpdateStart) / TIMEINTERVAL;
220 
221  return ((!newEdges.empty()) || hasNewForkEdges);
222 }
223 
225  NodePairSet& cpySrcNodes)
226 {
227  CallEdgeMap newForkEdges;
228  onTheFlyThreadCallGraphSolve(callsites, newForkEdges);
229  for (CallEdgeMap::iterator it = newForkEdges.begin(), eit = newForkEdges.end(); it != eit; it++)
230  {
231  for (FunctionSet::iterator cit = it->second.begin(),
232  ecit = it->second.end();
233  cit != ecit; ++cit)
234  {
235  connectCaller2ForkedFunParams(it->first, *cit, cpySrcNodes);
236  }
237  }
238  return !newForkEdges.empty();
239 }
240 
245  NodePairSet& cpySrcNodes)
246 {
247  assert(F);
248 
249  DBOUT(DAndersen, outs() << "connect parameters from indirect forksite "
250  << cs->valueOnlyToString() << " to forked function "
251  << *F << "\n");
252 
253  ThreadCallGraph *tdCallGraph = SVFUtil::dyn_cast<ThreadCallGraph>(callgraph);
254 
255  const PAGNode *cs_arg = tdCallGraph->getThreadAPI()->getActualParmAtForkSite(cs);
256  const PAGNode *fun_arg = tdCallGraph->getThreadAPI()->getFormalParmOfForkedFun(F);
257 
258  if(cs_arg->isPointer() && fun_arg->isPointer())
259  {
260  DBOUT(DAndersen, outs() << "process actual parm"
261  << cs_arg->toString() << "\n");
262  NodeID srcAA = sccRepNode(cs_arg->getId());
263  NodeID dstFA = sccRepNode(fun_arg->getId());
264  if (addCopyEdge(srcAA, dstFA))
265  {
266  cpySrcNodes.insert(std::make_pair(srcAA, dstFA));
267  }
268  }
269 }
270 
272 // * Connect formal and actual parameters for indirect callsites
273 // */
275  const SVFFunction* F, NodePairSet &cpySrcNodes)
276 {
277  assert(F);
278 
279  DBOUT(DAndersen, outs() << "connect parameters from indirect callsite " << cs->valueOnlyToString() << " to callee " << *F << "\n");
280 
281  const CallICFGNode* callBlockNode = cs;
282  const RetICFGNode* retBlockNode = cs->getRetICFGNode();
283 
284  if(SVFUtil::isHeapAllocExtFunViaRet(F) && pag->callsiteHasRet(retBlockNode))
285  {
286  heapAllocatorViaIndCall(cs,cpySrcNodes);
287  }
288 
289  if (pag->funHasRet(F) && pag->callsiteHasRet(retBlockNode))
290  {
291  const PAGNode* cs_return = pag->getCallSiteRet(retBlockNode);
292  const PAGNode* fun_return = pag->getFunRet(F);
293  if (cs_return->isPointer() && fun_return->isPointer())
294  {
295  NodeID dstrec = sccRepNode(cs_return->getId());
296  NodeID srcret = sccRepNode(fun_return->getId());
297  if(addCopyEdge(srcret, dstrec))
298  {
299  cpySrcNodes.insert(std::make_pair(srcret,dstrec));
300  }
301  }
302  else
303  {
304  DBOUT(DAndersen, outs() << "not a pointer ignored\n");
305  }
306  }
307 
308  if (pag->hasCallSiteArgsMap(callBlockNode) && pag->hasFunArgsList(F))
309  {
310 
311  // connect actual and formal param
312  const SVFIR::SVFVarList& csArgList = pag->getCallSiteArgsList(callBlockNode);
313  const SVFIR::SVFVarList& funArgList = pag->getFunArgsList(F);
314  //Go through the fixed parameters.
315  DBOUT(DPAGBuild, outs() << " args:");
316  SVFIR::SVFVarList::const_iterator funArgIt = funArgList.begin(), funArgEit = funArgList.end();
317  SVFIR::SVFVarList::const_iterator csArgIt = csArgList.begin(), csArgEit = csArgList.end();
318  for (; funArgIt != funArgEit; ++csArgIt, ++funArgIt)
319  {
320  //Some programs (e.g. Linux kernel) leave unneeded parameters empty.
321  if (csArgIt == csArgEit)
322  {
323  DBOUT(DAndersen, outs() << " !! not enough args\n");
324  break;
325  }
326  const PAGNode *cs_arg = *csArgIt ;
327  const PAGNode *fun_arg = *funArgIt;
328 
329  if (cs_arg->isPointer() && fun_arg->isPointer())
330  {
331  DBOUT(DAndersen, outs() << "process actual parm " << cs_arg->toString() << " \n");
332  NodeID srcAA = sccRepNode(cs_arg->getId());
333  NodeID dstFA = sccRepNode(fun_arg->getId());
334  if(addCopyEdge(srcAA, dstFA))
335  {
336  cpySrcNodes.insert(std::make_pair(srcAA,dstFA));
337  }
338  }
339  }
340 
341  //Any remaining actual args must be varargs.
342  if (F->isVarArg())
343  {
344  NodeID vaF = sccRepNode(pag->getVarargNode(F));
345  DBOUT(DPAGBuild, outs() << "\n varargs:");
346  for (; csArgIt != csArgEit; ++csArgIt)
347  {
348  const PAGNode *cs_arg = *csArgIt;
349  if (cs_arg->isPointer())
350  {
351  NodeID vnAA = sccRepNode(cs_arg->getId());
352  if (addCopyEdge(vnAA,vaF))
353  {
354  cpySrcNodes.insert(std::make_pair(vnAA,vaF));
355  }
356  }
357  }
358  }
359  if(csArgIt != csArgEit)
360  {
361  writeWrnMsg("too many args to non-vararg func.");
362  writeWrnMsg("(" + cs->getSourceLoc() + ")");
363  }
364  }
365 }
366 
368 {
369  assert(cs->getCalledFunction() == nullptr && "not an indirect callsite?");
370  const RetICFGNode* retBlockNode = cs->getRetICFGNode();
371  const PAGNode* cs_return = pag->getCallSiteRet(retBlockNode);
372  NodeID srcret;
373  CallSite2DummyValPN::const_iterator it = callsite2DummyValPN.find(cs);
374  if(it != callsite2DummyValPN.end())
375  {
376  srcret = sccRepNode(it->second);
377  }
378  else
379  {
380  NodeID valNode = pag->addDummyValNode();
381  NodeID objNode = pag->addDummyObjNode(cs->getType());
382  addPts(valNode,objNode);
383  callsite2DummyValPN.insert(std::make_pair(cs,valNode));
384  consCG->addConstraintNode(new ConstraintNode(valNode),valNode);
385  consCG->addConstraintNode(new ConstraintNode(objNode),objNode);
386  srcret = valNode;
387  }
388 
389  NodeID dstrec = sccRepNode(cs_return->getId());
390  if(addCopyEdge(srcret, dstrec))
391  cpySrcNodes.insert(std::make_pair(srcret,dstrec));
392 }
393 
395 {
396  SVFIR::MemObjToFieldsMap &memToFieldsMap = pag->getMemToFieldsMap();
397  SVFIR::NodeOffsetMap &GepObjVarMap = pag->getGepObjNodeMap();
398 
399  // clear GepObjVarMap/memToFieldsMap/nodeToSubsMap/nodeToRepMap
400  // for redundant gepnodes and remove those nodes from pag
401  for (NodeID n: redundantGepNodes)
402  {
403  NodeID base = pag->getBaseObjVar(n);
404  GepObjVar *gepNode = SVFUtil::dyn_cast<GepObjVar>(pag->getGNode(n));
405  assert(gepNode && "Not a gep node in redundantGepNodes set");
406  const APOffset apOffset = gepNode->getConstantFieldIdx();
407  GepObjVarMap.erase(std::make_pair(base, apOffset));
408  memToFieldsMap[base].reset(n);
409  cleanConsCG(n);
410 
411  pag->removeGNode(gepNode);
412  }
413 }
414 
419 {
420  resetData();
422 
423  if (Options::ClusterAnder()) cluster();
424 
426  processAllAddr();
427 }
428 
433 {
434  // TODO: check -stat too.
435  // TODO: broken
436  if (Options::ClusterAnder())
437  {
439  const PTDataTy *ptd = getPTDataTy();
440  // TODO: should we use liveOnly?
441  // TODO: parameterise final arg.
443  NodeIDAllocator::Clusterer::printStats("post-main", stats);
444  }
445 
448  // sanitizePts();
450 }
451 
456 {
457  // sub nodes do not need to be processed
458  if (sccRepNode(nodeId) != nodeId)
459  return;
460 
461  ConstraintNode* node = consCG->getConstraintNode(nodeId);
462  double insertStart = stat->getClk();
463  handleLoadStore(node);
464  double insertEnd = stat->getClk();
465  timeOfProcessLoadStore += (insertEnd - insertStart) / TIMEINTERVAL;
466 
467  double propStart = stat->getClk();
468  handleCopyGep(node);
469  double propEnd = stat->getClk();
470  timeOfProcessCopyGep += (propEnd - propStart) / TIMEINTERVAL;
471 }
472 
477 {
478  NodeID nodeId = node->getId();
479  computeDiffPts(nodeId);
480 
481  if (!getDiffPts(nodeId).empty())
482  {
483  for (ConstraintEdge* edge : node->getCopyOutEdges())
484  processCopy(nodeId, edge);
485  for (ConstraintEdge* edge : node->getGepOutEdges())
486  {
487  if (GepCGEdge* gepEdge = SVFUtil::dyn_cast<GepCGEdge>(edge))
488  processGep(nodeId, gepEdge);
489  }
490  }
491 }
492 
497 {
498  NodeID nodeId = node->getId();
499  for (PointsTo::iterator piter = getPts(nodeId).begin(), epiter =
500  getPts(nodeId).end(); piter != epiter; ++piter)
501  {
502  NodeID ptd = *piter;
503  // handle load
505  eit = node->outgoingLoadsEnd(); it != eit; ++it)
506  {
507  if (processLoad(ptd, *it))
508  pushIntoWorklist(ptd);
509  }
510 
511  // handle store
513  eit = node->incomingStoresEnd(); it != eit; ++it)
514  {
515  if (processStore(ptd, *it))
516  pushIntoWorklist((*it)->getSrcID());
517  }
518  }
519 }
520 
525 {
526  for (ConstraintGraph::const_iterator nodeIt = consCG->begin(), nodeEit = consCG->end(); nodeIt != nodeEit; nodeIt++)
527  {
528  ConstraintNode * cgNode = nodeIt->second;
529  for (ConstraintNode::const_iterator it = cgNode->incomingAddrsBegin(), eit = cgNode->incomingAddrsEnd();
530  it != eit; ++it)
531  processAddr(SVFUtil::cast<AddrCGEdge>(*it));
532  }
533 }
534 
539 {
540  numOfProcessedAddr++;
541 
542  NodeID dst = addr->getDstID();
543  NodeID src = addr->getSrcID();
544  if(addPts(dst,src))
545  pushIntoWorklist(dst);
546 }
547 
554 {
558 // if (pag->isBlkObjOrConstantObj(node))
559  if (pag->isConstantObj(node) || pag->getGNode(load->getDstID())->isPointer() == false)
560  return false;
561 
562  numOfProcessedLoad++;
563 
564  NodeID dst = load->getDstID();
565  return addCopyEdge(node, dst);
566 }
567 
574 {
578 // if (pag->isBlkObjOrConstantObj(node))
579  if (pag->isConstantObj(node) || pag->getGNode(store->getSrcID())->isPointer() == false)
580  return false;
581 
582  numOfProcessedStore++;
583 
584  NodeID src = store->getSrcID();
585  return addCopyEdge(src, node);
586 }
587 
594 {
595  numOfProcessedCopy++;
596 
597  assert((SVFUtil::isa<CopyCGEdge>(edge)) && "not copy/call/ret ??");
598  NodeID dst = edge->getDstID();
599  const PointsTo& srcPts = getDiffPts(node);
600 
601  bool changed = unionPts(dst, srcPts);
602  if (changed)
603  pushIntoWorklist(dst);
604  return changed;
605 }
606 
614 {
615  const PointsTo& srcPts = getDiffPts(edge->getSrcID());
616  return processGepPts(srcPts, edge);
617 }
618 
622 bool Andersen::processGepPts(const PointsTo& pts, const GepCGEdge* edge)
623 {
624  numOfProcessedGep++;
625 
626  PointsTo tmpDstPts;
627  if (SVFUtil::isa<VariantGepCGEdge>(edge))
628  {
629  // If a pointer is connected by a variant gep edge,
630  // then set this memory object to be field insensitive,
631  // unless the object is a black hole/constant.
632  for (NodeID o : pts)
633  {
634  if (consCG->isBlkObjOrConstantObj(o))
635  {
636  tmpDstPts.set(o);
637  continue;
638  }
639 
640  if (!isFieldInsensitive(o))
641  {
642  setObjFieldInsensitive(o);
643  consCG->addNodeToBeCollapsed(consCG->getBaseObjVar(o));
644  }
645 
646  // Add the field-insensitive node into pts.
647  NodeID baseId = consCG->getFIObjVar(o);
648  tmpDstPts.set(baseId);
649  }
650  }
651  else if (const NormalGepCGEdge* normalGepEdge = SVFUtil::dyn_cast<NormalGepCGEdge>(edge))
652  {
653  // TODO: after the node is set to field insensitive, handling invariant
654  // gep edge may lose precision because offsets here are ignored, and the
655  // base object is always returned.
656  for (NodeID o : pts)
657  {
658  if (consCG->isBlkObjOrConstantObj(o) || isFieldInsensitive(o))
659  {
660  tmpDstPts.set(o);
661  continue;
662  }
663 
664  NodeID fieldSrcPtdNode = consCG->getGepObjVar(o, normalGepEdge->getAccessPath().getConstantStructFldIdx());
665  tmpDstPts.set(fieldSrcPtdNode);
666  }
667  }
668  else
669  {
670  assert(false && "Andersen::processGepPts: New type GEP edge type?");
671  }
672 
673  NodeID dstId = edge->getDstID();
674  if (unionPts(dstId, tmpDstPts))
675  {
676  pushIntoWorklist(dstId);
677  return true;
678  }
679 
680  return false;
681 }
682 
687 {
688  // If a node is a PWC node, collapse all its points-to target.
689  // collapseNodePts() may change the points-to set of the nodes which have been processed
690  // before, in this case, we may need to re-do the analysis.
691  if (consCG->isPWCNode(nodeId) && collapseNodePts(nodeId))
692  reanalyze = true;
693 }
694 
696 {
697  while (consCG->hasNodesToBeCollapsed())
698  {
699  NodeID node = consCG->getNextCollapseNode();
700  // collapseField() may change the points-to set of the nodes which have been processed
701  // before, in this case, we may need to re-do the analysis.
702  if (collapseField(node))
703  reanalyze = true;
704  }
705 }
706 
707 /*
708  * Merge constraint graph nodes based on SCC cycle detected.
709  */
711 {
712  NodeStack revTopoOrder;
713  NodeStack & topoOrder = getSCCDetector()->topoNodeStack();
714  while (!topoOrder.empty())
715  {
716  NodeID repNodeId = topoOrder.top();
717  topoOrder.pop();
718  revTopoOrder.push(repNodeId);
719  const NodeBS& subNodes = getSCCDetector()->subNodes(repNodeId);
720  // merge sub nodes to rep node
721  mergeSccNodes(repNodeId, subNodes);
722  }
723 
724  // restore the topological order for later solving.
725  while (!revTopoOrder.empty())
726  {
727  NodeID nodeId = revTopoOrder.top();
728  revTopoOrder.pop();
729  topoOrder.push(nodeId);
730  }
731 }
732 
733 
738 void Andersen::mergeSccNodes(NodeID repNodeId, const NodeBS& subNodes)
739 {
740  for (NodeBS::iterator nodeIt = subNodes.begin(); nodeIt != subNodes.end(); nodeIt++)
741  {
742  NodeID subNodeId = *nodeIt;
743  if (subNodeId != repNodeId)
744  {
745  mergeNodeToRep(subNodeId, repNodeId);
746  }
747  }
748 }
749 
754 {
755  bool changed = false;
756  const PointsTo& nodePts = getPts(nodeId);
758  PointsTo ptsClone = nodePts;
759  for (PointsTo::iterator ptsIt = ptsClone.begin(), ptsEit = ptsClone.end(); ptsIt != ptsEit; ptsIt++)
760  {
761  if (isFieldInsensitive(*ptsIt))
762  continue;
763 
764  if (collapseField(*ptsIt))
765  changed = true;
766  }
767  return changed;
768 }
769 
774 {
779  if (consCG->isBlkObjOrConstantObj(nodeId))
780  return false;
781 
782  bool changed = false;
783 
784  double start = stat->getClk();
785 
786  // set base node field-insensitive.
787  setObjFieldInsensitive(nodeId);
788 
789  // replace all occurrences of each field with the field-insensitive node
790  NodeID baseId = consCG->getFIObjVar(nodeId);
791  NodeID baseRepNodeId = consCG->sccRepNode(baseId);
792  NodeBS & allFields = consCG->getAllFieldsObjVars(baseId);
793  for (NodeBS::iterator fieldIt = allFields.begin(), fieldEit = allFields.end(); fieldIt != fieldEit; fieldIt++)
794  {
795  NodeID fieldId = *fieldIt;
796  if (fieldId != baseId)
797  {
798  // use the reverse pts of this field node to find all pointers point to it
799  const NodeSet revPts = getRevPts(fieldId);
800  for (const NodeID o : revPts)
801  {
802  // change the points-to target from field to base node
803  clearPts(o, fieldId);
804  addPts(o, baseId);
805  pushIntoWorklist(o);
806 
807  changed = true;
808  }
809  // merge field node into base node, including edges and pts.
810  NodeID fieldRepNodeId = consCG->sccRepNode(fieldId);
811  mergeNodeToRep(fieldRepNodeId, baseRepNodeId);
812  if (fieldId != baseRepNodeId)
813  {
814  // gep node fieldId becomes redundant if it is merged to its base node who is set as field-insensitive
815  // two node IDs should be different otherwise this field is actually the base and should not be removed.
816  redundantGepNodes.set(fieldId);
817  }
818  }
819  }
820 
821  if (consCG->isPWCNode(baseRepNodeId))
822  if (collapseNodePts(baseRepNodeId))
823  changed = true;
824 
825  double end = stat->getClk();
826  timeOfCollapse += (end - start) / TIMEINTERVAL;
827 
828  return changed;
829 }
830 
835 {
836  numOfSCCDetection++;
837 
838  double sccStart = stat->getClk();
840  double sccEnd = stat->getClk();
841 
842  timeOfSCCDetection += (sccEnd - sccStart)/TIMEINTERVAL;
843 
844  double mergeStart = stat->getClk();
845 
846  mergeSccCycle();
847 
848  double mergeEnd = stat->getClk();
849 
850  timeOfSCCMerges += (mergeEnd - mergeStart)/TIMEINTERVAL;
851 
852  return getSCCDetector()->topoNodeStack();
853 }
854 
858 bool Andersen::mergeSrcToTgt(NodeID nodeId, NodeID newRepId)
859 {
860 
861  if(nodeId==newRepId)
862  return false;
863 
865  updatePropaPts(newRepId, nodeId);
866  unionPts(newRepId,nodeId);
867 
869  ConstraintNode* node = consCG->getConstraintNode(nodeId);
870  bool pwc = consCG->moveEdgesToRepNode(node, consCG->getConstraintNode(newRepId));
871 
876  if(node->isPWCNode())
877  pwc = true;
878 
880  updateNodeRepAndSubs(node->getId(),newRepId);
881 
882  consCG->removeConstraintNode(node);
883 
884  return pwc;
885 }
886 /*
887  * Merge a node to its rep node based on SCC detection
888  */
890 {
891 
892  if (mergeSrcToTgt(nodeId,newRepId))
893  consCG->setPWCNode(newRepId);
894 }
895 
896 /*
897  * Updates subnodes of its rep, and rep node of its subs
898  */
900 {
901  consCG->setRep(nodeId,newRepId);
902  NodeBS repSubs;
903  repSubs.set(nodeId);
905  // update nodeToSubsMap, union its subs with its rep Subs
906  NodeBS& nodeSubs = consCG->sccSubNodes(nodeId);
907  for(NodeBS::iterator sit = nodeSubs.begin(), esit = nodeSubs.end(); sit!=esit; ++sit)
908  {
909  NodeID subId = *sit;
910  consCG->setRep(subId,newRepId);
911  }
912  repSubs |= nodeSubs;
913  consCG->setSubs(newRepId,repSubs);
914  consCG->resetSubs(nodeId);
915 }
916 
917 void Andersen::cluster(void) const
918 {
919  assert(Options::MaxFieldLimit() == 0 && "Andersen::cluster: clustering for Andersen's is currently only supported in field-insensitive analysis");
921  std::vector<std::pair<unsigned, unsigned>> keys;
922  for (SVFIR::iterator pit = pag->begin(); pit != pag->end(); ++pit)
923  {
924  keys.push_back(std::make_pair(pit->first, 1));
925  }
926 
927  std::vector<std::pair<hclust_fast_methods, std::vector<NodeID>>> candidates;
928  PointsTo::MappingPtr nodeMapping =
929  std::make_shared<std::vector<NodeID>>(NodeIDAllocator::Clusterer::cluster(steens, keys, candidates, "aux-steens"));
930  PointsTo::MappingPtr reverseNodeMapping =
931  std::make_shared<std::vector<NodeID>>(NodeIDAllocator::Clusterer::getReverseNodeMapping(*nodeMapping));
932 
933  PointsTo::setCurrentBestNodeMapping(nodeMapping, reverseNodeMapping);
934 }
935 
940 {
941  for (OrderedNodeSet::iterator nIter = this->getAllValidPtrs().begin();
942  nIter != this->getAllValidPtrs().end(); ++nIter)
943  {
944  const PAGNode* node = getPAG()->getGNode(*nIter);
945  if (getPAG()->isValidTopLevelPtr(node))
946  {
947  const PointsTo& pts = this->getPts(node->getId());
948  outs() << "\nNodeID " << node->getId() << " ";
949 
950  if (pts.empty())
951  {
952  outs() << "\t\tPointsTo: {empty}\n";
953  }
954  else
955  {
956  outs() << "\t\tPointsTo: { ";
957 
958  multiset<u32_t> line;
959  for (PointsTo::iterator it = pts.begin(), eit = pts.end();
960  it != eit; ++it)
961  {
962  line.insert(*it);
963  }
964  for (multiset<u32_t>::const_iterator it = line.begin(); it != line.end(); ++it)
965  {
967  if (auto gepNode = SVFUtil::dyn_cast<GepObjVar>(pag->getGNode(*it)))
968  outs() << gepNode->getBaseNode() << "_" << gepNode->getConstantFieldIdx() << " ";
969  else
970  outs() << *it << " ";
971  else
972  outs() << *it << " ";
973  }
974  outs() << "}\n";
975  }
976  }
977  }
978 
979  outs().flush();
980 }
981 
unsigned u32_t
Definition: CommandLine.h:18
#define F(f)
#define DBOUT(TYPE, X)
LLVM debug macros, define type of your DBUG model of each pass.
Definition: SVFType.h:484
#define TIMEINTERVAL
Definition: SVFType.h:512
#define DGENERAL
Definition: SVFType.h:490
#define DPAGBuild
Definition: SVFType.h:492
#define DAndersen
Definition: SVFType.h:503
cJSON * n
Definition: cJSON.cpp:2558
const char *const string
Definition: cJSON.h:172
static double timeOfSCCMerges
Definition: Andersen.h:167
static u32_t numOfProcessedCopy
Number of processed Addr edge.
Definition: Andersen.h:158
static u32_t numOfSCCDetection
Definition: Andersen.h:165
virtual void normalizePointsTo() override
static u32_t numOfSfrs
Number of processed Store edge.
Definition: Andersen.h:162
virtual void finalize() override
Finalize analysis.
Definition: Andersen.cpp:89
static double timeOfUpdateCallGraph
Definition: Andersen.h:173
static u32_t numOfProcessedStore
Number of processed Load edge.
Definition: Andersen.h:161
virtual void connectCaller2CalleeParams(const CallICFGNode *cs, const SVFFunction *F, NodePairSet &cpySrcNodes)
Connect formal and actual parameters for indirect callsites.
static u32_t numOfProcessedAddr
Statistics.
Definition: Andersen.h:157
virtual bool updateCallGraph(const CallSiteToFunPtrMap &) override
Update call graph.
Definition: Andersen.cpp:190
void heapAllocatorViaIndCall(const CallICFGNode *cs, NodePairSet &cpySrcNodes)
virtual void readPtsFromFile(const std::string &filename)
Definition: Andersen.cpp:157
static u32_t numOfProcessedLoad
Number of processed Gep edge.
Definition: Andersen.h:160
static double timeOfSCCDetection
Definition: Andersen.h:166
virtual void initialize() override
Initialize analysis.
Definition: Andersen.cpp:73
~AndersenBase() override
Destructor.
Definition: Andersen.cpp:64
virtual void analyze() override
Andersen analysis.
Definition: Andersen.cpp:133
static u32_t numOfFieldExpand
Definition: Andersen.h:163
static double timeOfProcessLoadStore
Definition: Andersen.h:172
static u32_t numOfProcessedGep
Number of processed Copy edge.
Definition: Andersen.h:159
static double timeOfProcessCopyGep
Definition: Andersen.h:171
static u32_t MaxPointsToSetSize
Definition: Andersen.h:170
virtual void solveConstraints()
Definition: Andersen.cpp:100
virtual bool updateThreadCallGraph(const CallSiteToFunPtrMap &, NodePairSet &)
Update thread call graph.
Definition: Andersen.cpp:224
static double timeOfCollapse
Definition: Andersen.h:168
static u32_t AveragePointsToSetSize
Definition: Andersen.h:169
virtual void solveAndwritePtsToFile(const std::string &filename)
Definition: Andersen.cpp:168
void cleanConsCG(NodeID id)
remove redundant gepnodes in constraint graph
Definition: Andersen.cpp:180
virtual void connectCaller2ForkedFunParams(const CallICFGNode *cs, const SVFFunction *F, NodePairSet &cpySrcNodes)
Connect formal and actual parameters for indirect forksites.
Definition: Andersen.cpp:244
virtual void handleLoadStore(ConstraintNode *node)
Definition: Andersen.cpp:496
void mergeSccNodes(NodeID repNodeId, const NodeBS &subNodes)
Merge sub node in a SCC cycle to their rep node.
Definition: Andersen.cpp:738
virtual void processNode(NodeID nodeId)
Override WPASolver function in order to use the default solver.
Definition: Andersen.cpp:455
virtual void initialize()
Initialize analysis.
Definition: Andersen.cpp:418
virtual NodeStack & SCCDetect()
SCC detection.
Definition: Andersen.cpp:834
virtual void mergeNodeToRep(NodeID nodeId, NodeID newRepId)
Merge sub node to its rep.
Definition: Andersen.cpp:889
bool collapseNodePts(NodeID nodeId)
Definition: Andersen.cpp:753
void dumpTopLevelPtsTo()
Definition: Andersen.cpp:939
virtual bool processGep(NodeID node, const GepCGEdge *edge)
Definition: Andersen.cpp:613
virtual void handleCopyGep(ConstraintNode *node)
Definition: Andersen.cpp:476
virtual bool processLoad(NodeID node, const ConstraintEdge *load)
Definition: Andersen.cpp:553
void collapseFields()
collapse positive weight cycles of a graph
Definition: Andersen.cpp:695
virtual bool processStore(NodeID node, const ConstraintEdge *load)
Definition: Andersen.cpp:573
virtual bool processCopy(NodeID node, const ConstraintEdge *edge)
Definition: Andersen.cpp:593
virtual bool processGepPts(const PointsTo &pts, const GepCGEdge *edge)
Definition: Andersen.cpp:622
void mergeSccCycle()
Definition: Andersen.cpp:710
virtual void processAddr(const AddrCGEdge *addr)
Definition: Andersen.cpp:538
void updateNodeRepAndSubs(NodeID nodeId, NodeID newRepId)
Updates subnodes of its rep, and rep node of its subs.
Definition: Andersen.cpp:899
virtual void finalize()
Finalize analysis.
Definition: Andersen.cpp:432
void processAllAddr()
handling various constraints
Definition: Andersen.cpp:524
virtual void cluster(void) const
Definition: Andersen.cpp:917
virtual bool mergeSrcToTgt(NodeID srcId, NodeID tgtId)
Definition: Andersen.cpp:858
virtual void collapsePWCNode(NodeID nodeId)
Collapse a field object into its base for field insensitive analysis.
Definition: Andersen.cpp:686
bool collapseField(NodeID nodeId)
Definition: Andersen.cpp:773
void finalize() override
Finalization of pointer analysis, and normalize points-to information to Bit Vector representation.
const SVFFunction * getCalledFunction() const
Definition: ICFGNode.h:518
const std::string getSourceLoc() const override
Definition: ICFGNode.h:588
const RetICFGNode * getRetICFGNode() const
Return callsite.
Definition: ICFGNode.h:457
bool isPWCNode() const
Whether a node involves in PWC, if so, all its points-to elements should become field-insensitive.
Definition: ConsGNode.h:81
const_iterator outgoingLoadsEnd() const
Definition: ConsGNode.h:194
const_iterator incomingAddrsBegin() const
Definition: ConsGNode.h:181
const ConstraintEdge::ConstraintEdgeSetTy & getGepOutEdges() const
Definition: ConsGNode.h:123
const_iterator incomingStoresBegin() const
Definition: ConsGNode.h:215
const_iterator incomingStoresEnd() const
Definition: ConsGNode.h:219
ConstraintEdge::ConstraintEdgeSetTy::const_iterator const_iterator
Definition: ConsGNode.h:45
const ConstraintEdge::ConstraintEdgeSetTy & getCopyOutEdges() const
Definition: ConsGNode.h:115
const_iterator incomingAddrsEnd() const
Definition: ConsGNode.h:185
const_iterator outgoingLoadsBegin() const
Definition: ConsGNode.h:190
NodeID getDstID() const
Definition: GenericGraph.h:85
NodeID getSrcID() const
get methods of the components
Definition: GenericGraph.h:81
IDToNodeMapTy::iterator iterator
Node Iterators.
Definition: GenericGraph.h:606
APOffset getConstantFieldIdx() const
offset of the mem object
Definition: SVFVariables.h:500
NodeID getBaseNode(void) const
Return the base object from which this GEP node came from.
Definition: SVFVariables.h:512
static std::vector< NodeID > cluster(BVDataPTAImpl *pta, const std::vector< std::pair< NodeID, unsigned >> keys, std::vector< std::pair< hclust_fast_methods, std::vector< NodeID >>> &candidates, std::string evalSubtitle="")
static std::vector< NodeID > getReverseNodeMapping(const std::vector< NodeID > &nodeMapping)
static void printStats(std::string title, Map< std::string, std::string > &stats)
static void evaluate(const std::vector< NodeID > &nodeMap, const Map< PointsTo, unsigned > pointsToSets, Map< std::string, std::string > &stats, bool accountForOcc)
Fills in *NumWords statistics in stats..
static const Option< u32_t > AnderTimeLimit
Time limit for the Andersen's analyses.
Definition: Options.h:75
static const Option< bool > PrintFieldWithBasePrefix
Definition: Options.h:118
static const Option< std::string > ReadAnder
Definition: Options.h:214
static const Option< bool > ClusterAnder
Whether to stage Andersen's with Steensgaard and cluster based on that data.
Definition: Options.h:41
static const Option< bool > PrintCGGraph
Definition: Options.h:210
static const Option< u32_t > MaxFieldLimit
Maximum number of field derivations for an object.
Definition: Options.h:38
static const Option< std::string > WriteAnder
Definition: Options.h:212
static const Option< bool > ConsCGDotGraph
Definition: Options.h:208
virtual Map< DataSet, unsigned > getAllPts(bool liveOnly) const =0
OrderedMap< const CallICFGNode *, FunctionSet > CallEdgeMap
virtual void initialize()
Initialization of a pointer analysis, including building symbol table and SVFIR etc.
SVFIR::CallSiteToFunPtrMap CallSiteToFunPtrMap
bool empty() const
Returns true if set is empty.
Definition: PointsTo.cpp:98
const_iterator end() const
Definition: PointsTo.h:132
std::shared_ptr< std::vector< NodeID > > MappingPtr
Definition: PointsTo.h:42
static void setCurrentBestNodeMapping(MappingPtr newCurrentBestNodeMapping, MappingPtr newCurrentBestReverseNodeMapping)
Definition: PointsTo.cpp:371
void set(u32_t n)
Inserts n in the set.
Definition: PointsTo.cpp:157
const_iterator begin() const
Definition: PointsTo.h:128
static MappingPtr getCurrentBestNodeMapping()
Definition: PointsTo.cpp:361
virtual const SVFType * getType() const
Definition: GenericGraph.h:271
NodeID getId() const
Get ID.
Definition: GenericGraph.h:260
const std::string valueOnlyToString() const
Definition: LLVMUtil.cpp:688
std::vector< const SVFVar * > SVFVarList
Definition: SVFIR.h:59
Map< NodeID, NodeBS > MemObjToFieldsMap
Definition: SVFIR.h:57
Map< NodeOffset, NodeID > NodeOffsetMap
Definition: SVFIR.h:70
virtual bool isPointer() const
Whether it is a pointer.
Definition: SVFVariables.h:106
virtual const std::string toString() const
iterator end() const
void set(unsigned Idx)
iterator begin() const
static Steensgaard * createSteensgaard(SVFIR *_pag)
Create an singleton instance.
Definition: Steensgaard.h:31
const SVFVar * getFormalParmOfForkedFun(const SVFFunction *F) const
Return the formal parm of forked function (the first arg in pthread)
Definition: ThreadAPI.cpp:184
const SVFVar * getActualParmAtForkSite(const CallICFGNode *inst) const
Definition: ThreadAPI.cpp:178
ThreadAPI * getThreadAPI() const
Thread API.
virtual NodeStack & SCCDetect()
SCC detection.
Definition: WPASolver.h:86
void stopAnalysisLimitTimer(bool limitTimerSet)
Definition: SVFUtil.cpp:310
bool isHeapAllocExtFunViaRet(const SVFFunction *fun)
Return true if the call is a heap allocator/reallocator.
Definition: SVFUtil.h:296
std::string pasMsg(const std::string &msg)
Print each pass/phase message by converting a string into blue string output.
Definition: SVFUtil.cpp:99
bool startAnalysisLimitTimer(unsigned timeLimit)
Definition: SVFUtil.cpp:289
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
std::stack< NodeID > NodeStack
Definition: GeneralType.h:118
Set< NodeID > NodeSet
Definition: GeneralType.h:113
u32_t NodeID
Definition: GeneralType.h:55
s64_t APOffset
Definition: GeneralType.h:60
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
Definition: GeneralType.h:101
Set< NodePair > NodePairSet
Definition: GeneralType.h:114