svf-tools 1.0.1073 → 1.0.1075

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build.sh CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svf-tools",
3
- "version": "1.0.1073",
3
+ "version": "1.0.1075",
4
4
  "description": "* <b>[TypeClone](https://github.com/SVF-tools/SVF/wiki/TypeClone) published in our [ECOOP paper](https://yuleisui.github.io/publications/ecoop20.pdf) is now available in SVF </b> * <b>SVF now uses a single script for its build. Just type [`source ./build.sh`](https://github.com/SVF-tools/SVF/blob/master/build.sh) in your terminal, that's it!</b> * <b>SVF now supports LLVM-10.0.0! </b> * <b>We thank [bsauce](https://github.com/bsauce) for writing a user manual of SVF ([link1](https://www.jianshu.com/p/068a08ec749c) and [link2](https://www.jianshu.com/p/777c30d4240e)) in Chinese </b> * <b>SVF now supports LLVM-9.0.0 (Thank [Byoungyoung Lee](https://github.com/SVF-tools/SVF/issues/142) for his help!). </b> * <b>SVF now supports a set of [field-sensitive pointer analyses](https://yuleisui.github.io/publications/sas2019a.pdf). </b> * <b>[Use SVF as an external lib](https://github.com/SVF-tools/SVF/wiki/Using-SVF-as-a-lib-in-your-own-tool) for your own project (Contributed by [Hongxu Chen](https://github.com/HongxuChen)). </b> * <b>SVF now supports LLVM-7.0.0. </b> * <b>SVF now supports Docker. [Try SVF in Docker](https://github.com/SVF-tools/SVF/wiki/Try-SVF-in-Docker)! </b> * <b>SVF now supports [LLVM-6.0.0](https://github.com/svf-tools/SVF/pull/38) (Contributed by [Jack Anthony](https://github.com/jackanth)). </b> * <b>SVF now supports [LLVM-4.0.0](https://github.com/svf-tools/SVF/pull/23) (Contributed by Jared Carlson. Thank [Jared](https://github.com/jcarlson23) and [Will](https://github.com/dtzWill) for their in-depth [discussions](https://github.com/svf-tools/SVF/pull/18) about updating SVF!) </b> * <b>SVF now supports analysis for C++ programs.</b> <br />",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -36,6 +36,7 @@
36
36
 
37
37
  #include "Graphs/ICFG.h"
38
38
  #include "Graphs/WTO.h"
39
+ #include "Graphs/CallGraph.h"
39
40
 
40
41
  namespace SVF
41
42
  {
@@ -77,6 +78,58 @@ public:
77
78
  }
78
79
  }
79
80
  };
81
+
82
+ // Added for IWTO
83
+ class ICFGIWTO : public ICFGWTO
84
+ {
85
+ public:
86
+ typedef ICFGWTO Base;
87
+ typedef WTOComponentVisitor<ICFG>::WTONodeT ICFGWTONode;
88
+ NodeBS &funcPar;
89
+ CallGraph *cg;
90
+
91
+ explicit ICFGIWTO(ICFG* graph, const ICFGNode* node, NodeBS & funcPar, CallGraph* cg) :
92
+ Base(graph, node), funcPar(funcPar), cg(cg) {}
93
+
94
+ virtual ~ICFGIWTO()
95
+ {
96
+ }
97
+
98
+ inline void forEachSuccessor(
99
+ const ICFGNode* node,
100
+ std::function<void(const ICFGNode*)> func) const override
101
+ {
102
+ if (const auto* callNode = SVFUtil::dyn_cast<CallICFGNode>(node))
103
+ {
104
+
105
+ for (const auto &e : callNode->getOutEdges())
106
+ {
107
+ ICFGNode *calleeEntryICFGNode = e->getDstNode();
108
+ CallGraphNode * calleeCGNode = cg->getCallGraphNode(calleeEntryICFGNode->getFun());
109
+
110
+ const ICFGNode* succ = nullptr;
111
+ if (funcPar.test(calleeCGNode->getId()))
112
+ succ = calleeEntryICFGNode;
113
+ else
114
+ succ = callNode->getRetICFGNode();
115
+
116
+ func(succ);
117
+ }
118
+ }
119
+ else
120
+ {
121
+ for (const auto& e : node->getOutEdges())
122
+ {
123
+ ICFGNode *succ = e->getDstNode();
124
+ CallGraphNode *succCGNode = cg->getCallGraphNode(succ->getFun());
125
+ if (!funcPar.test(succCGNode->getId()))
126
+ continue;
127
+ func(succ);
128
+ }
129
+ }
130
+ }
131
+ };
132
+
80
133
  } // namespace SVF
81
134
 
82
135
  #endif // SVF_ICFGWTO_H
@@ -28,9 +28,7 @@
28
28
  #include "AE/Core/AbstractState.h"
29
29
  #include "AE/Core/ICFGWTO.h"
30
30
  #include "AE/Svfexe/AEDetector.h"
31
- #include "AE/Svfexe/AbsExtAPI.h"
32
31
  #include "Util/SVFBugReport.h"
33
- #include "WPA/Andersen.h"
34
32
 
35
33
  namespace SVF
36
34
  {
@@ -33,7 +33,8 @@
33
33
  #include "AE/Svfexe/AEDetector.h"
34
34
  #include "AE/Svfexe/AbsExtAPI.h"
35
35
  #include "Util/SVFBugReport.h"
36
- #include "WPA/Andersen.h"
36
+ #include "Util/SVFStat.h"
37
+ #include "Graphs/SCC.h"
37
38
 
38
39
  namespace SVF
39
40
  {
@@ -107,6 +108,29 @@ class AbstractInterpretation
107
108
 
108
109
  public:
109
110
  typedef SCCDetection<CallGraph*> CallGraphSCC;
111
+
112
+ /*
113
+ * For recursive test case
114
+ * int demo(int a) {
115
+ if (a >= 10000)
116
+ return a;
117
+ demo(a+1);
118
+ }
119
+
120
+ int main() {
121
+ int result = demo(0);
122
+ }
123
+ * if set TOP, result = [-oo, +oo] since the return value, and any stored object pointed by q at *q = p in recursive functions will be set to the top value.
124
+ * if set WIDEN_ONLY, result = [10000, +oo] since only widening is applied at the cycle head of recursive functions without narrowing.
125
+ * if set WIDEN_NARROW, result = [10000, 10000] since both widening and narrowing are applied at the cycle head of recursive functions.
126
+ * */
127
+ enum HandleRecur
128
+ {
129
+ TOP,
130
+ WIDEN_ONLY,
131
+ WIDEN_NARROW
132
+ };
133
+
110
134
  /// Constructor
111
135
  AbstractInterpretation();
112
136
 
@@ -135,7 +159,7 @@ private:
135
159
  /// Global ICFGNode is handled at the entry of the program,
136
160
  virtual void handleGlobalNode();
137
161
 
138
- /// Mark recursive functions in the call graph
162
+ /// Compute IWTO for each function partition entry
139
163
  void initWTO();
140
164
 
141
165
  /**
@@ -251,7 +275,8 @@ private:
251
275
  AEStat* stat;
252
276
 
253
277
  std::vector<const CallICFGNode*> callSiteStack;
254
- Map<const FunObjVar*, ICFGWTO*> funcToWTO;
278
+ Map<const FunObjVar*, const ICFGWTO*> funcToWTO;
279
+ Set<std::pair<const CallICFGNode*, NodeID>> nonRecursiveCallSites;
255
280
  Set<const FunObjVar*> recursiveFuns;
256
281
 
257
282
 
@@ -282,8 +307,10 @@ private:
282
307
  // helper functions in handleCallSite
283
308
  virtual bool isExtCall(const CallICFGNode* callNode);
284
309
  virtual void extCallPass(const CallICFGNode* callNode);
310
+ virtual bool isRecursiveFun(const FunObjVar* fun);
285
311
  virtual bool isRecursiveCall(const CallICFGNode* callNode);
286
- virtual void recursiveCallPass(const CallICFGNode* callNode);
312
+ virtual void recursiveCallPass(const CallICFGNode *callNode);
313
+ virtual bool isRecursiveCallSite(const CallICFGNode* callNode, const FunObjVar *);
287
314
  virtual bool isDirectCall(const CallICFGNode* callNode);
288
315
  virtual void directCallFunPass(const CallICFGNode* callNode);
289
316
  virtual bool isIndirectCall(const CallICFGNode* callNode);
@@ -11,6 +11,7 @@
11
11
  #include "Util/NodeIDAllocator.h"
12
12
  #include "MSSA/MemSSA.h"
13
13
  #include "WPA/WPAPass.h"
14
+ #include "AE/Svfexe/AbstractInterpretation.h"
14
15
 
15
16
  namespace SVF
16
17
  {
@@ -244,6 +245,8 @@ public:
244
245
 
245
246
  // Abstract Execution
246
247
  static const Option<u32_t> WidenDelay;
248
+ /// recursion handling mode, Default: TOP
249
+ static const OptionMap<AbstractInterpretation::HandleRecur> HandleRecur;
247
250
  /// the max time consumptions (seconds). Default: 4 hours 14400s
248
251
  static const Option<u32_t> Timeout;
249
252
  /// bug info output file, Default: output.db
@@ -26,6 +26,8 @@
26
26
  //
27
27
  #include "AE/Svfexe/AbsExtAPI.h"
28
28
  #include "AE/Svfexe/AbstractInterpretation.h"
29
+ #include "WPA/Andersen.h"
30
+ #include "Util/Options.h"
29
31
 
30
32
  using namespace SVF;
31
33
  AbsExtAPI::AbsExtAPI(Map<const ICFGNode*, AbstractState>& traces): abstractTrace(traces)
@@ -31,6 +31,7 @@
31
31
  #include "Util/Options.h"
32
32
  #include "Util/WorkList.h"
33
33
  #include "Graphs/CallGraph.h"
34
+ #include "WPA/Andersen.h"
34
35
  #include <cmath>
35
36
 
36
37
  using namespace SVF;
@@ -68,15 +69,16 @@ AbstractInterpretation::~AbstractInterpretation()
68
69
  delete stat;
69
70
  for (auto it: funcToWTO)
70
71
  delete it.second;
71
-
72
72
  }
73
73
 
74
74
  /**
75
- * @brief Mark recursive functions in the call graph
75
+ * @brief Compute WTO for each function partition entry
76
76
  *
77
- * This function identifies and marks recursive functions in the call graph.
78
- * It does this by detecting cycles in the call graph's strongly connected components (SCC).
79
- * Any function found to be part of a cycle is marked as recursive.
77
+ * This function first identifies function partition entries (pair: <entry, function set>),
78
+ * and then compute the IWTO for each pair.
79
+ * It does this by detecting call graph's strongly connected components (SCC).
80
+ * Each SCC forms a function partition, and any function that is invoked from outside its SCC
81
+ * is identified as an entry of the function partition.
80
82
  */
81
83
  void AbstractInterpretation::initWTO()
82
84
  {
@@ -84,21 +86,74 @@ void AbstractInterpretation::initWTO()
84
86
  // Detect if the call graph has cycles by finding its strongly connected components (SCC)
85
87
  Andersen::CallGraphSCC* callGraphScc = ander->getCallGraphSCC();
86
88
  callGraphScc->find();
87
- CallGraph* svfirCallGraph = PAG::getPAG()->getCallGraph();
89
+ CallGraph* callGraph = ander->getCallGraph();
88
90
 
89
91
  // Iterate through the call graph
90
- for (auto it = svfirCallGraph->begin(); it != svfirCallGraph->end(); it++)
92
+ for (auto it = callGraph->begin(); it != callGraph->end(); it++)
91
93
  {
92
94
  // Check if the current function is part of a cycle
93
95
  if (callGraphScc->isInCycle(it->second->getId()))
94
96
  recursiveFuns.insert(it->second->getFunction()); // Mark the function as recursive
95
- if (it->second->getFunction()->isDeclaration())
96
- continue;
97
- auto* wto = new ICFGWTO(icfg, icfg->getFunEntryICFGNode(it->second->getFunction()));
98
- wto->init();
99
- funcToWTO[it->second->getFunction()] = wto;
97
+
98
+ // In TOP mode, calculate the WTO
99
+ if (Options::HandleRecur() == TOP)
100
+ {
101
+ if (it->second->getFunction()->isDeclaration())
102
+ continue;
103
+ auto* wto = new ICFGWTO(icfg, icfg->getFunEntryICFGNode(it->second->getFunction()));
104
+ wto->init();
105
+ funcToWTO[it->second->getFunction()] = wto;
106
+ }
107
+ // In WIDEN_TOP or WIDEN_NARROW mode, calculate the IWTO
108
+ else if (Options::HandleRecur() == WIDEN_ONLY ||
109
+ Options::HandleRecur() == WIDEN_NARROW)
110
+ {
111
+ const FunObjVar *fun = it->second->getFunction();
112
+ if (fun->isDeclaration())
113
+ continue;
114
+
115
+ NodeID repNodeId = callGraphScc->repNode(it->second->getId());
116
+ auto cgSCCNodes = callGraphScc->subNodes(repNodeId);
117
+
118
+ // Identify if this node is an SCC entry (nodes who have incoming edges
119
+ // from nodes outside the SCC). Also identify non-recursive callsites.
120
+ bool isEntry = false;
121
+ if (it->second->getInEdges().empty())
122
+ isEntry = true;
123
+ for (auto inEdge: it->second->getInEdges())
124
+ {
125
+ NodeID srcNodeId = inEdge->getSrcID();
126
+ if (!cgSCCNodes.test(srcNodeId))
127
+ {
128
+ isEntry = true;
129
+ const CallICFGNode *callSite = nullptr;
130
+ if (inEdge->isDirectCallEdge())
131
+ callSite = *(inEdge->getDirectCalls().begin());
132
+ else if (inEdge->isIndirectCallEdge())
133
+ callSite = *(inEdge->getIndirectCalls().begin());
134
+ else
135
+ assert(false && "CallGraphEdge must "
136
+ "be either direct or indirect!");
137
+
138
+ nonRecursiveCallSites.insert(
139
+ {callSite, inEdge->getDstNode()->getFunction()->getId()});
140
+ }
141
+ }
142
+
143
+ // Compute IWTO for the function partition entered from each partition entry
144
+ if (isEntry)
145
+ {
146
+ ICFGIWTO* iwto = new ICFGIWTO(icfg, icfg->getFunEntryICFGNode(fun),
147
+ cgSCCNodes, callGraph);
148
+ iwto->init();
149
+ funcToWTO[it->second->getFunction()] = iwto;
150
+ }
151
+ }
152
+ else
153
+ assert(false && "Invalid recursion mode specified!");
100
154
  }
101
155
  }
156
+
102
157
  /// Program entry
103
158
  void AbstractInterpretation::analyse()
104
159
  {
@@ -109,7 +164,7 @@ void AbstractInterpretation::analyse()
109
164
  icfg->getGlobalICFGNode())[PAG::getPAG()->getBlkPtr()] = IntervalValue::top();
110
165
  if (const CallGraphNode* cgn = svfir->getCallGraph()->getCallGraphNode("main"))
111
166
  {
112
- ICFGWTO* wto = funcToWTO[cgn->getFunction()];
167
+ const ICFGWTO* wto = funcToWTO[cgn->getFunction()];
113
168
  handleWTOComponents(wto->getWTOComponents());
114
169
  }
115
170
  }
@@ -138,27 +193,57 @@ bool AbstractInterpretation::mergeStatesFromPredecessors(const ICFGNode * icfgNo
138
193
  {
139
194
  if (abstractTrace.find(edge->getSrcNode()) != abstractTrace.end())
140
195
  {
141
- const IntraCFGEdge *intraCfgEdge = SVFUtil::dyn_cast<IntraCFGEdge>(edge);
142
- if (intraCfgEdge && intraCfgEdge->getCondition())
196
+
197
+ if (const IntraCFGEdge *intraCfgEdge =
198
+ SVFUtil::dyn_cast<IntraCFGEdge>(edge))
143
199
  {
144
200
  AbstractState tmpEs = abstractTrace[edge->getSrcNode()];
145
- if (isBranchFeasible(intraCfgEdge, tmpEs))
201
+ if (intraCfgEdge->getCondition())
146
202
  {
147
- workList.push_back(tmpEs);
203
+ if (isBranchFeasible(intraCfgEdge, tmpEs))
204
+ {
205
+ workList.push_back(tmpEs);
206
+ }
207
+ else
208
+ {
209
+ // do nothing
210
+ }
148
211
  }
149
212
  else
150
213
  {
151
- // do nothing
214
+ workList.push_back(tmpEs);
152
215
  }
153
216
  }
154
- else
217
+ else if (const CallCFGEdge *callCfgEdge =
218
+ SVFUtil::dyn_cast<CallCFGEdge>(edge))
155
219
  {
156
- workList.push_back(abstractTrace[edge->getSrcNode()]);
157
- }
158
- }
159
- else
160
- {
161
220
 
221
+ // context insensitive implementation
222
+ workList.push_back(
223
+ abstractTrace[callCfgEdge->getSrcNode()]);
224
+ }
225
+ else if (const RetCFGEdge *retCfgEdge =
226
+ SVFUtil::dyn_cast<RetCFGEdge>(edge))
227
+ {
228
+ switch (Options::HandleRecur())
229
+ {
230
+ case TOP:
231
+ {
232
+ workList.push_back(abstractTrace[retCfgEdge->getSrcNode()]);
233
+ break;
234
+ }
235
+ case WIDEN_ONLY:
236
+ case WIDEN_NARROW:
237
+ {
238
+ const RetICFGNode* returnSite = SVFUtil::dyn_cast<RetICFGNode>(icfgNode);
239
+ const CallICFGNode* callSite = returnSite->getCallICFGNode();
240
+ if (hasAbsStateFromTrace(callSite))
241
+ workList.push_back(abstractTrace[retCfgEdge->getSrcNode()]);
242
+ }
243
+ }
244
+ }
245
+ else
246
+ assert(false && "Unhandled ICFGEdge type encountered!");
162
247
  }
163
248
  }
164
249
  if (workList.size() == 0)
@@ -502,7 +587,7 @@ void AbstractInterpretation::handleSingletonWTO(const ICFGSingletonWTO *icfgSing
502
587
  }
503
588
 
504
589
  /**
505
- * @brief Hanlde two types of WTO components (singleton and cycle)
590
+ * @brief Handle two types of WTO components (singleton and cycle)
506
591
  */
507
592
  void AbstractInterpretation::handleWTOComponents(const std::list<const ICFGWTOComp*>& wtoComps)
508
593
  {
@@ -512,7 +597,7 @@ void AbstractInterpretation::handleWTOComponents(const std::list<const ICFGWTOCo
512
597
  }
513
598
  }
514
599
 
515
- void AbstractInterpretation::handleWTOComponent(const SVF::ICFGWTOComp* wtoNode)
600
+ void AbstractInterpretation::handleWTOComponent(const ICFGWTOComp* wtoNode)
516
601
  {
517
602
  if (const ICFGSingletonWTO* node = SVFUtil::dyn_cast<ICFGSingletonWTO>(wtoNode))
518
603
  {
@@ -527,9 +612,7 @@ void AbstractInterpretation::handleWTOComponent(const SVF::ICFGWTOComp* wtoNode)
527
612
  }
528
613
  // Assert false for unknown WTO types
529
614
  else
530
- {
531
615
  assert(false && "unknown WTO type!");
532
- }
533
616
  }
534
617
 
535
618
  void AbstractInterpretation::handleCallSite(const ICFGNode* node)
@@ -540,7 +623,7 @@ void AbstractInterpretation::handleCallSite(const ICFGNode* node)
540
623
  {
541
624
  extCallPass(callNode);
542
625
  }
543
- else if (isRecursiveCall(callNode))
626
+ else if (isRecursiveCall(callNode) && Options::HandleRecur() == TOP)
544
627
  {
545
628
  recursiveCallPass(callNode);
546
629
  }
@@ -553,22 +636,18 @@ void AbstractInterpretation::handleCallSite(const ICFGNode* node)
553
636
  indirectCallFunPass(callNode);
554
637
  }
555
638
  else
556
- {
557
639
  assert(false && "implement this part");
558
- }
559
640
  }
560
641
  else
561
- {
562
642
  assert (false && "it is not call node");
563
- }
564
643
  }
565
644
 
566
- bool AbstractInterpretation::isExtCall(const SVF::CallICFGNode *callNode)
645
+ bool AbstractInterpretation::isExtCall(const CallICFGNode *callNode)
567
646
  {
568
647
  return SVFUtil::isExtCall(callNode->getCalledFunction());
569
648
  }
570
649
 
571
- void AbstractInterpretation::extCallPass(const SVF::CallICFGNode *callNode)
650
+ void AbstractInterpretation::extCallPass(const CallICFGNode *callNode)
572
651
  {
573
652
  callSiteStack.push_back(callNode);
574
653
  utils->handleExtAPI(callNode);
@@ -579,16 +658,21 @@ void AbstractInterpretation::extCallPass(const SVF::CallICFGNode *callNode)
579
658
  callSiteStack.pop_back();
580
659
  }
581
660
 
582
- bool AbstractInterpretation::isRecursiveCall(const SVF::CallICFGNode *callNode)
661
+ bool AbstractInterpretation::isRecursiveFun(const FunObjVar* fun)
662
+ {
663
+ return recursiveFuns.find(fun) != recursiveFuns.end();
664
+ }
665
+
666
+ bool AbstractInterpretation::isRecursiveCall(const CallICFGNode *callNode)
583
667
  {
584
668
  const FunObjVar *callfun = callNode->getCalledFunction();
585
669
  if (!callfun)
586
670
  return false;
587
671
  else
588
- return recursiveFuns.find(callfun) != recursiveFuns.end();
672
+ return isRecursiveFun(callfun);
589
673
  }
590
674
 
591
- void AbstractInterpretation::recursiveCallPass(const SVF::CallICFGNode *callNode)
675
+ void AbstractInterpretation::recursiveCallPass(const CallICFGNode *callNode)
592
676
  {
593
677
  AbstractState& as = getAbsStateFromTrace(callNode);
594
678
  SkipRecursiveCall(callNode);
@@ -607,23 +691,37 @@ void AbstractInterpretation::recursiveCallPass(const SVF::CallICFGNode *callNode
607
691
  abstractTrace[retNode] = as;
608
692
  }
609
693
 
610
- bool AbstractInterpretation::isDirectCall(const SVF::CallICFGNode *callNode)
694
+ bool AbstractInterpretation::isRecursiveCallSite(const CallICFGNode* callNode,
695
+ const FunObjVar* callee)
696
+ {
697
+ return nonRecursiveCallSites.find({callNode, callee->getId()}) ==
698
+ nonRecursiveCallSites.end();
699
+ }
700
+
701
+ bool AbstractInterpretation::isDirectCall(const CallICFGNode *callNode)
611
702
  {
612
703
  const FunObjVar *callfun =callNode->getCalledFunction();
613
704
  if (!callfun)
614
705
  return false;
615
706
  else
616
- return funcToWTO.find(callfun) != funcToWTO.end();
707
+ return !callfun->isDeclaration();
617
708
  }
618
- void AbstractInterpretation::directCallFunPass(const SVF::CallICFGNode *callNode)
709
+ void AbstractInterpretation::directCallFunPass(const CallICFGNode *callNode)
619
710
  {
620
711
  AbstractState& as = getAbsStateFromTrace(callNode);
621
- callSiteStack.push_back(callNode);
622
712
 
623
713
  abstractTrace[callNode] = as;
624
714
 
625
- const FunObjVar *callfun =callNode->getCalledFunction();
626
- ICFGWTO* wto = funcToWTO[callfun];
715
+ const FunObjVar *calleeFun =callNode->getCalledFunction();
716
+ if (Options::HandleRecur() == WIDEN_ONLY || Options::HandleRecur() == WIDEN_NARROW)
717
+ {
718
+ if (isRecursiveCallSite(callNode, calleeFun))
719
+ return;
720
+ }
721
+
722
+ callSiteStack.push_back(callNode);
723
+
724
+ const ICFGWTO* wto = funcToWTO[calleeFun];
627
725
  handleWTOComponents(wto->getWTOComponents());
628
726
 
629
727
  callSiteStack.pop_back();
@@ -633,13 +731,13 @@ void AbstractInterpretation::directCallFunPass(const SVF::CallICFGNode *callNode
633
731
  abstractTrace[retNode] = abstractTrace[callNode];
634
732
  }
635
733
 
636
- bool AbstractInterpretation::isIndirectCall(const SVF::CallICFGNode *callNode)
734
+ bool AbstractInterpretation::isIndirectCall(const CallICFGNode *callNode)
637
735
  {
638
736
  const auto callsiteMaps = svfir->getIndirectCallsites();
639
737
  return callsiteMaps.find(callNode) != callsiteMaps.end();
640
738
  }
641
739
 
642
- void AbstractInterpretation::indirectCallFunPass(const SVF::CallICFGNode *callNode)
740
+ void AbstractInterpretation::indirectCallFunPass(const CallICFGNode *callNode)
643
741
  {
644
742
  AbstractState& as = getAbsStateFromTrace(callNode);
645
743
  const auto callsiteMaps = svfir->getIndirectCallsites();
@@ -651,13 +749,20 @@ void AbstractInterpretation::indirectCallFunPass(const SVF::CallICFGNode *callNo
651
749
  AbstractValue Addrs = as[call_id];
652
750
  NodeID addr = *Addrs.getAddrs().begin();
653
751
  SVFVar *func_var = svfir->getGNode(AbstractState::getInternalID(addr));
654
- if(const FunObjVar*funObjVar = SVFUtil::dyn_cast<FunObjVar>(func_var))
752
+
753
+ if(const FunObjVar* funObjVar = SVFUtil::dyn_cast<FunObjVar>(func_var))
655
754
  {
755
+ if (Options::HandleRecur() == WIDEN_ONLY || Options::HandleRecur() == WIDEN_NARROW)
756
+ {
757
+ if (isRecursiveCallSite(callNode, funObjVar))
758
+ return;
759
+ }
760
+
656
761
  const FunObjVar* callfun = funObjVar->getFunction();
657
762
  callSiteStack.push_back(callNode);
658
763
  abstractTrace[callNode] = as;
659
764
 
660
- ICFGWTO* wto = funcToWTO[callfun];
765
+ const ICFGWTO* wto = funcToWTO[callfun];
661
766
  handleWTOComponents(wto->getWTOComponents());
662
767
  callSiteStack.pop_back();
663
768
  // handle Ret node
@@ -666,8 +771,6 @@ void AbstractInterpretation::indirectCallFunPass(const SVF::CallICFGNode *callNo
666
771
  }
667
772
  }
668
773
 
669
-
670
-
671
774
  /// handle wto cycle (loop)
672
775
  void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle)
673
776
  {
@@ -686,8 +789,32 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle)
686
789
  AbstractState cur_head_state = abstractTrace[cycle_head];
687
790
  if (increasing)
688
791
  {
689
- // Widening phase
690
- abstractTrace[cycle_head] = prev_head_state.widening(cur_head_state);
792
+ // Widening, use different modes for nodes within recursions
793
+ if (isRecursiveFun(cycle->head()->getICFGNode()->getFun()))
794
+ {
795
+ // For nodes in recursions, widen to top in WIDEN_TOP mode
796
+ if (Options::HandleRecur() == WIDEN_ONLY)
797
+ {
798
+ abstractTrace[cycle_head] = prev_head_state.widening(cur_head_state);
799
+ }
800
+ // Perform normal widening in WIDEN_NARROW mode
801
+ else if (Options::HandleRecur() == WIDEN_NARROW)
802
+ {
803
+ abstractTrace[cycle_head] = prev_head_state.widening(cur_head_state);
804
+ }
805
+ // In TOP mode, skipRecursiveCall will handle recursions,
806
+ // thus should not reach this branch
807
+ else
808
+ {
809
+ assert(false && "Recursion mode TOP should not reach here!");
810
+ }
811
+ }
812
+ // For nodes outside recursions, perform normal widening
813
+ else
814
+ {
815
+ abstractTrace[cycle_head] = prev_head_state.widening(cur_head_state);
816
+ }
817
+
691
818
  if (abstractTrace[cycle_head] == prev_head_state)
692
819
  {
693
820
  increasing = false;
@@ -696,19 +823,49 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle)
696
823
  }
697
824
  else
698
825
  {
699
- // Widening's fixpoint reached in the widening phase, switch to narrowing
700
- abstractTrace[cycle_head] = prev_head_state.narrowing(cur_head_state);
701
- if (abstractTrace[cycle_head] == prev_head_state)
826
+ // Narrowing, use different modes for nodes within recursions
827
+ if (isRecursiveFun(cycle->head()->getICFGNode()->getFun()))
702
828
  {
703
- // Narrowing's fixpoint reached in the narrowing phase, exit loop
704
- break;
829
+ // For nodes in recursions, skip narrowing in WIDEN_TOP mode
830
+ if (Options::HandleRecur() == WIDEN_ONLY)
831
+ {
832
+ break;
833
+ }
834
+ // Perform normal narrowing in WIDEN_NARROW mode
835
+ else if (Options::HandleRecur() == WIDEN_NARROW)
836
+ {
837
+ // Widening's fixpoint reached in the widening phase, switch to narrowing
838
+ abstractTrace[cycle_head] = prev_head_state.narrowing(cur_head_state);
839
+ if (abstractTrace[cycle_head] == prev_head_state)
840
+ {
841
+ // Narrowing's fixpoint reached in the narrowing phase, exit loop
842
+ break;
843
+ }
844
+ }
845
+ // In TOP mode, skipRecursiveCall will handle recursions,
846
+ // thus should not reach this branch
847
+ else
848
+ {
849
+ assert(false && "Recursion mode TOP should not reach here");
850
+ }
851
+ }
852
+ // For nodes outside recursions, perform normal narrowing
853
+ else
854
+ {
855
+ // Widening's fixpoint reached in the widening phase, switch to narrowing
856
+ abstractTrace[cycle_head] = prev_head_state.narrowing(cur_head_state);
857
+ if (abstractTrace[cycle_head] == prev_head_state)
858
+ {
859
+ // Narrowing's fixpoint reached in the narrowing phase, exit loop
860
+ break;
861
+ }
705
862
  }
706
863
  }
707
864
  }
708
865
  else
709
866
  {
710
867
  // Handle the cycle head
711
- handleSingletonWTO(cycle->head());
868
+ handleWTOComponent(cycle->head());
712
869
  }
713
870
  // Handle the cycle body
714
871
  handleWTOComponents(cycle->getWTOComponents());
@@ -773,7 +930,6 @@ void AbstractInterpretation::handleSVFStatement(const SVFStmt *stmt)
773
930
  assert(false && "implement this part");
774
931
  }
775
932
 
776
-
777
933
  void AbstractInterpretation::SkipRecursiveCall(const CallICFGNode *callNode)
778
934
  {
779
935
  AbstractState& as = getAbsStateFromTrace(callNode);
@@ -1212,10 +1368,8 @@ void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp)
1212
1368
  resVal = IntervalValue(1, 1);
1213
1369
  break;
1214
1370
  default:
1215
- {
1216
1371
  assert(false && "undefined compare: ");
1217
1372
  }
1218
- }
1219
1373
  as[res] = resVal;
1220
1374
  }
1221
1375
  else if (as[op0].isAddr() && as[op1].isAddr())
@@ -1328,10 +1482,8 @@ void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp)
1328
1482
  resVal = IntervalValue(1, 1);
1329
1483
  break;
1330
1484
  default:
1331
- {
1332
1485
  assert(false && "undefined compare: ");
1333
1486
  }
1334
- }
1335
1487
  as[res] = resVal;
1336
1488
  }
1337
1489
  }
@@ -1389,9 +1541,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy)
1389
1541
  // we only support i64 at most
1390
1542
  }
1391
1543
  else
1392
- {
1393
1544
  assert(false && "cannot support int type other than u8/16/32/64");
1394
- }
1395
1545
  }
1396
1546
  else
1397
1547
  {
@@ -1401,7 +1551,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy)
1401
1551
  return IntervalValue::top(); // TODO: may have better solution
1402
1552
  };
1403
1553
 
1404
- auto getTruncValue = [&](const AbstractState& as, const SVF::SVFVar* var,
1554
+ auto getTruncValue = [&](const AbstractState& as, const SVFVar* var,
1405
1555
  const SVFType* dstType)
1406
1556
  {
1407
1557
  const IntervalValue& itv = as[var->getId()].getInterval();
@@ -1448,9 +1598,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy)
1448
1598
  return IntervalValue(s32_lb, s32_ub);
1449
1599
  }
1450
1600
  else
1451
- {
1452
1601
  assert(false && "cannot support dst int type other than u8/16/32");
1453
- }
1454
1602
  };
1455
1603
 
1456
1604
  AbstractState& as = getAbsStateFromTrace(copy->getICFGNode());
@@ -1513,10 +1661,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy)
1513
1661
  }
1514
1662
  }
1515
1663
  else
1516
- {
1517
1664
  assert(false && "undefined copy kind");
1518
- abort();
1519
- }
1520
1665
  }
1521
1666
 
1522
1667
 
@@ -779,6 +779,25 @@ const Option<u32_t> Options::LoopBound(
779
779
 
780
780
  const Option<u32_t> Options::WidenDelay(
781
781
  "widen-delay", "Loop Widen Delay", 3);
782
+ const OptionMap<AbstractInterpretation::HandleRecur> Options::HandleRecur(
783
+ "handle-recur",
784
+ "Recursion handling mode in abstract execution (Default -widen-narrow)",
785
+ AbstractInterpretation::HandleRecur::WIDEN_NARROW,
786
+ {
787
+ {
788
+ AbstractInterpretation::HandleRecur::TOP, "top",
789
+ "The return value, and any stored object pointed by q at *q = p in recursive functions will be set to the top value."
790
+ },
791
+ {
792
+ AbstractInterpretation::HandleRecur::WIDEN_ONLY, "widen-only",
793
+ "Only apply widening at the cycle head of recursive functions."
794
+ },
795
+ {
796
+ AbstractInterpretation::HandleRecur::WIDEN_NARROW, "widen-narrow",
797
+ "Apply both widening and narrowing at the cycle head of recursive functions."
798
+ }
799
+ }
800
+ );
782
801
  const Option<u32_t> Options::Timeout(
783
802
  "timeout", "time out (seconds), set -1 (no timeout), default 14400s",14400);
784
803
  const Option<std::string> Options::OutputName(
@@ -887,6 +887,7 @@ int main(int argc, char** argv)
887
887
  ae.addDetector(std::make_unique<BufOverflowDetector>());
888
888
  ae.runOnModule(pag->getICFG());
889
889
 
890
+ AndersenWaveDiff::releaseAndersenWaveDiff();
890
891
  LLVMModuleSet::releaseLLVMModuleSet();
891
892
 
892
893
  return 0;