svf-tools 1.0.1199 → 1.0.1201

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svf-tools",
3
- "version": "1.0.1199",
3
+ "version": "1.0.1201",
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": {
@@ -32,6 +32,7 @@
32
32
  #include "AE/Core/AbstractState.h"
33
33
  #include "AE/Core/ICFGWTO.h"
34
34
  #include "AE/Svfexe/AEDetector.h"
35
+ #include "AE/Svfexe/PreAnalysis.h"
35
36
  #include "AE/Svfexe/AbsExtAPI.h"
36
37
  #include "Util/SVFBugReport.h"
37
38
  #include "Util/SVFStat.h"
@@ -111,8 +112,6 @@ class AbstractInterpretation
111
112
  friend class NullptrDerefDetector;
112
113
 
113
114
  public:
114
- typedef SCCDetection<CallGraph*> CallGraphSCC;
115
-
116
115
  /*
117
116
  * For recursive test case
118
117
  * int demo(int a) {
@@ -189,9 +188,6 @@ private:
189
188
  /// Global ICFGNode is handled at the entry of the program,
190
189
  virtual void handleGlobalNode();
191
190
 
192
- /// Compute IWTO for each function partition entry
193
- void initWTO();
194
-
195
191
  /**
196
192
  * Check if execution state exist by merging states of predecessor nodes
197
193
  *
@@ -260,13 +256,6 @@ private:
260
256
  */
261
257
  std::vector<const ICFGNode*> getNextNodesOfCycle(const ICFGCycleWTO* cycle) const;
262
258
 
263
- /**
264
- * Recursively collect cycle heads from nested WTO components
265
- *
266
- * @param comps The list of WTO components to collect cycle heads from
267
- */
268
- void collectCycleHeads(const std::list<const ICFGWTOComp*>& comps);
269
-
270
259
  /**
271
260
  * handle SVF Statement like CmpStmt, CallStmt, GepStmt, LoadStmt, StoreStmt, etc.
272
261
  *
@@ -333,10 +322,7 @@ private:
333
322
  CallGraph* callGraph;
334
323
  AEStat* stat;
335
324
 
336
- Map<const FunObjVar*, const ICFGWTO*> funcToWTO;
337
- Set<std::pair<const CallICFGNode*, NodeID>> nonRecursiveCallSites;
338
- Set<const FunObjVar*> recursiveFuns;
339
- Map<const ICFGNode*, const ICFGCycleWTO*> cycleHeadToCycle;
325
+ PreAnalysis* preAnalysis{nullptr};
340
326
 
341
327
 
342
328
  bool hasAbsStateFromTrace(const ICFGNode* node)
@@ -353,8 +339,7 @@ private:
353
339
  virtual bool isExtCall(const CallICFGNode* callNode);
354
340
  virtual void handleExtCall(const CallICFGNode* callNode);
355
341
  virtual bool isRecursiveFun(const FunObjVar* fun);
356
- virtual bool isRecursiveCall(const CallICFGNode* callNode);
357
- virtual void recursiveCallPass(const CallICFGNode *callNode);
342
+ virtual void handleRecursiveCall(const CallICFGNode *callNode);
358
343
  virtual bool isRecursiveCallSite(const CallICFGNode* callNode, const FunObjVar *);
359
344
  virtual void handleFunCall(const CallICFGNode* callNode);
360
345
 
@@ -0,0 +1,81 @@
1
+ //===- PreAnalysis.h -- Pre-Analysis for Abstract Interpretation----------//
2
+ //
3
+ // SVF: Static Value-Flow Analysis
4
+ //
5
+ // Copyright (C) <2013-> <Yulei Sui>
6
+ //
7
+
8
+ // This program is free software: you can redistribute it and/or modify
9
+ // it under the terms of the GNU Affero General Public License as published by
10
+ // the Free Software Foundation, either version 3 of the License, or
11
+ // (at your option) any later version.
12
+
13
+ // This program is distributed in the hope that it will be useful,
14
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ // GNU Affero General Public License for more details.
17
+
18
+ // You should have received a copy of the GNU Affero General Public License
19
+ // along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ //
21
+ //===----------------------------------------------------------------------===//
22
+
23
+ /*
24
+ * PreAnalysis.h
25
+ *
26
+ * Created on: Feb 25, 2026
27
+ * Author: Jiawei Wang
28
+ *
29
+ * This file provides a pre-analysis phase for Abstract Interpretation.
30
+ * It runs Andersen's pointer analysis and builds WTO (Weak Topological Order)
31
+ * for each function before the main abstract interpretation.
32
+ */
33
+
34
+ #ifndef INCLUDE_AE_SVFEXE_PREANALYSIS_H_
35
+ #define INCLUDE_AE_SVFEXE_PREANALYSIS_H_
36
+
37
+ #include "SVFIR/SVFIR.h"
38
+ #include "Graphs/ICFG.h"
39
+ #include "Graphs/CallGraph.h"
40
+ #include "Graphs/SCC.h"
41
+ #include "AE/Core/ICFGWTO.h"
42
+ #include "WPA/Andersen.h"
43
+
44
+ namespace SVF
45
+ {
46
+
47
+ class PreAnalysis
48
+ {
49
+ public:
50
+ typedef SCCDetection<CallGraph*> CallGraphSCC;
51
+
52
+ PreAnalysis(SVFIR* pag, ICFG* icfg);
53
+ virtual ~PreAnalysis();
54
+
55
+ /// Accessors for Andersen's results
56
+ AndersenWaveDiff* getPointerAnalysis() const { return pta; }
57
+ CallGraph* getCallGraph() const { return callGraph; }
58
+ CallGraphSCC* getCallGraphSCC() const { return callGraphSCC; }
59
+
60
+ /// Build WTO for each function using call graph SCC
61
+ void initWTO();
62
+
63
+ /// Accessors for WTO data
64
+ const Map<const FunObjVar*, const ICFGWTO*>& getFuncToWTO() const
65
+ {
66
+ return funcToWTO;
67
+ }
68
+
69
+ private:
70
+ SVFIR* svfir;
71
+ ICFG* icfg;
72
+ AndersenWaveDiff* pta;
73
+ CallGraph* callGraph;
74
+ CallGraphSCC* callGraphSCC;
75
+
76
+ Map<const FunObjVar*, const ICFGWTO*> funcToWTO;
77
+ };
78
+
79
+ } // End namespace SVF
80
+
81
+ #endif /* INCLUDE_AE_SVFEXE_PREANALYSIS_H_ */
@@ -48,6 +48,12 @@ void AbstractInterpretation::runOnModule(ICFG *_icfg)
48
48
  svfir = PAG::getPAG();
49
49
  utils = new AbsExtAPI(abstractTrace);
50
50
 
51
+ // Run Andersen's pointer analysis and build WTO
52
+ preAnalysis = new PreAnalysis(svfir, icfg);
53
+ callGraph = preAnalysis->getCallGraph();
54
+ icfg->updateCallGraph(callGraph);
55
+ preAnalysis->initWTO();
56
+
51
57
  /// collect checkpoint
52
58
  collectCheckPoint();
53
59
 
@@ -63,103 +69,13 @@ void AbstractInterpretation::runOnModule(ICFG *_icfg)
63
69
 
64
70
  AbstractInterpretation::AbstractInterpretation()
65
71
  {
66
- AndersenWaveDiff* ander = AndersenWaveDiff::createAndersenWaveDiff(svfir);
67
- callGraph = ander->getCallGraph();
68
72
  stat = new AEStat(this);
69
73
  }
70
74
  /// Destructor
71
75
  AbstractInterpretation::~AbstractInterpretation()
72
76
  {
73
77
  delete stat;
74
- for (auto it: funcToWTO)
75
- delete it.second;
76
- }
77
-
78
- /**
79
- * @brief Recursively collect cycle heads from nested WTO components
80
- *
81
- * This helper function traverses the WTO component tree and builds the cycleHeadToCycle
82
- * map, which maps each cycle head node to its corresponding ICFGCycleWTO object.
83
- * This enables efficient O(1) lookup of cycles during analysis.
84
- */
85
- void AbstractInterpretation::collectCycleHeads(const std::list<const ICFGWTOComp*>& comps)
86
- {
87
- for (const ICFGWTOComp* comp : comps)
88
- {
89
- if (const ICFGCycleWTO* cycle = SVFUtil::dyn_cast<ICFGCycleWTO>(comp))
90
- {
91
- cycleHeadToCycle[cycle->head()->getICFGNode()] = cycle;
92
- // Recursively collect nested cycle heads
93
- collectCycleHeads(cycle->getWTOComponents());
94
- }
95
- }
96
- }
97
-
98
- void AbstractInterpretation::initWTO()
99
- {
100
- AndersenWaveDiff* ander = AndersenWaveDiff::createAndersenWaveDiff(svfir);
101
- CallGraphSCC* callGraphScc = ander->getCallGraphSCC();
102
- callGraphScc->find();
103
- // Iterate through the call graph
104
- for (auto it = callGraph->begin(); it != callGraph->end(); it++)
105
- {
106
- // Check if the current function is part of a cycle
107
- if (callGraphScc->isInCycle(it->second->getId()))
108
- recursiveFuns.insert(it->second->getFunction()); // Mark the function as recursive
109
-
110
- // Calculate ICFGWTO for each function/recursion
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
- Set<const FunObjVar*> funcScc;
147
- for (const auto& node: cgSCCNodes)
148
- {
149
- funcScc.insert(callGraph->getGNode(node)->getFunction());
150
- }
151
- ICFGWTO* iwto = new ICFGWTO(icfg->getFunEntryICFGNode(fun), funcScc);
152
- iwto->init();
153
- funcToWTO[it->second->getFunction()] = iwto;
154
- }
155
- }
156
-
157
- // Build cycleHeadToCycle map for all functions
158
- // This maps cycle head nodes to their corresponding WTO cycles for efficient lookup
159
- for (auto& [func, wto] : funcToWTO)
160
- {
161
- collectCycleHeads(wto->getWTOComponents());
162
- }
78
+ delete preAnalysis;
163
79
  }
164
80
 
165
81
  /// Collect entry point functions for analysis.
@@ -200,8 +116,6 @@ std::deque<const FunObjVar*> AbstractInterpretation::collectProgEntryFuns()
200
116
  /// Program entry - analyze from all entry points (multi-entry analysis is the default)
201
117
  void AbstractInterpretation::analyse()
202
118
  {
203
- initWTO();
204
-
205
119
  // Always use multi-entry analysis from all entry points
206
120
  analyzeFromAllProgEntries();
207
121
  }
@@ -814,8 +728,8 @@ std::vector<const ICFGNode*> AbstractInterpretation::getNextNodesOfCycle(const I
814
728
  */
815
729
  void AbstractInterpretation::handleFunction(const ICFGNode* funEntry, const CallICFGNode* caller)
816
730
  {
817
- auto it = funcToWTO.find(funEntry->getFun());
818
- if (it == funcToWTO.end())
731
+ auto it = preAnalysis->getFuncToWTO().find(funEntry->getFun());
732
+ if (it == preAnalysis->getFuncToWTO().end())
819
733
  return;
820
734
 
821
735
  // Push all top-level WTO components into the worklist in WTO order
@@ -872,21 +786,11 @@ void AbstractInterpretation::handleExtCall(const CallICFGNode *callNode)
872
786
  /// Check if a function is recursive (part of a call graph SCC)
873
787
  bool AbstractInterpretation::isRecursiveFun(const FunObjVar* fun)
874
788
  {
875
- return recursiveFuns.find(fun) != recursiveFuns.end();
876
- }
877
-
878
- /// Check if a call node calls a recursive function
879
- bool AbstractInterpretation::isRecursiveCall(const CallICFGNode *callNode)
880
- {
881
- const FunObjVar *callfun = callNode->getCalledFunction();
882
- if (!callfun)
883
- return false;
884
- else
885
- return isRecursiveFun(callfun);
789
+ return preAnalysis->getPointerAnalysis()->isInRecursion(fun);
886
790
  }
887
791
 
888
792
  /// Handle recursive call in TOP mode: set all stores and return value to TOP
889
- void AbstractInterpretation::recursiveCallPass(const CallICFGNode *callNode)
793
+ void AbstractInterpretation::handleRecursiveCall(const CallICFGNode *callNode)
890
794
  {
891
795
  AbstractState& as = getAbsStateFromTrace(callNode);
892
796
  setTopToObjInRecursion(callNode);
@@ -905,12 +809,12 @@ void AbstractInterpretation::recursiveCallPass(const CallICFGNode *callNode)
905
809
  abstractTrace[retNode] = as;
906
810
  }
907
811
 
908
- /// Check if a call is a recursive callsite (within same SCC, not entry call from outside)
812
+ /// Check if caller and callee are in the same CallGraph SCC (i.e. a recursive callsite)
909
813
  bool AbstractInterpretation::isRecursiveCallSite(const CallICFGNode* callNode,
910
814
  const FunObjVar* callee)
911
815
  {
912
- return nonRecursiveCallSites.find({callNode, callee->getId()}) ==
913
- nonRecursiveCallSites.end();
816
+ const FunObjVar* caller = callNode->getCaller();
817
+ return preAnalysis->getPointerAnalysis()->inSameCallGraphSCC(caller, callee);
914
818
  }
915
819
 
916
820
  /// Get callee function: directly for direct calls, via pointer analysis for indirect calls
@@ -1013,7 +917,7 @@ void AbstractInterpretation::handleFunCall(const CallICFGNode *callNode)
1013
917
  }
1014
918
 
1015
919
  // Indirect call: use Andersen's call graph to get all resolved callees.
1016
- // The call graph was built during initWTO() by running Andersen's pointer analysis,
920
+ // The call graph was built during PreAnalysis::initWTO() by running Andersen's pointer analysis,
1017
921
  // which over-approximates the set of possible targets for each indirect callsite.
1018
922
  if (callGraph->hasIndCSCallees(callNode))
1019
923
  {
@@ -1051,7 +955,7 @@ void AbstractInterpretation::handleFunCall(const CallICFGNode *callNode)
1051
955
  /// Behavior depends on Options::HandleRecur():
1052
956
  ///
1053
957
  /// - TOP mode:
1054
- /// Does not iterate. Calls recursiveCallPass() to set all stores and
958
+ /// Does not iterate. Calls handleRecursiveCall() to set all stores and
1055
959
  /// return value to TOP immediately. This is the most conservative but fastest.
1056
960
  /// Example:
1057
961
  /// int factorial(int n) { return n <= 1 ? 1 : n * factorial(n-1); }
@@ -1074,13 +978,13 @@ void AbstractInterpretation::handleLoopOrRecursion(const ICFGCycleWTO* cycle, co
1074
978
  {
1075
979
  const ICFGNode* cycle_head = cycle->head()->getICFGNode();
1076
980
 
1077
- // TOP mode for recursive function cycles: use recursiveCallPass to set
981
+ // TOP mode for recursive function cycles: use handleRecursiveCall to set
1078
982
  // all stores and return value to TOP, maintaining original semantics
1079
983
  if (Options::HandleRecur() == TOP && isRecursiveFun(cycle_head->getFun()))
1080
984
  {
1081
985
  if (caller)
1082
986
  {
1083
- recursiveCallPass(caller);
987
+ handleRecursiveCall(caller);
1084
988
  }
1085
989
  return;
1086
990
  }
@@ -0,0 +1,84 @@
1
+ //===- PreAnalysis.cpp -- Pre-Analysis for Abstract Interpretation---------//
2
+ //
3
+ // SVF: Static Value-Flow Analysis
4
+ //
5
+ // Copyright (C) <2013-> <Yulei Sui>
6
+ //
7
+
8
+ // This program is free software: you can redistribute it and/or modify
9
+ // it under the terms of the GNU Affero General Public License as published by
10
+ // the Free Software Foundation, either version 3 of the License, or
11
+ // (at your option) any later version.
12
+
13
+ // This program is distributed in the hope that it will be useful,
14
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ // GNU Affero General Public License for more details.
17
+
18
+ // You should have received a copy of the GNU Affero General Public License
19
+ // along with this program. If not, see <http://www.gnu.org/licenses/>.
20
+ //
21
+ //===----------------------------------------------------------------------===//
22
+
23
+ /*
24
+ * PreAnalysis.cpp
25
+ *
26
+ * Created on: Feb 25, 2026
27
+ * Author: Jiawei Wang
28
+ */
29
+
30
+ #include "AE/Svfexe/PreAnalysis.h"
31
+
32
+ using namespace SVF;
33
+
34
+ PreAnalysis::PreAnalysis(SVFIR* pag, ICFG* icfg)
35
+ : svfir(pag), icfg(icfg)
36
+ {
37
+ pta = AndersenWaveDiff::createAndersenWaveDiff(svfir);
38
+ callGraph = pta->getCallGraph();
39
+ callGraphSCC = pta->getCallGraphSCC();
40
+ }
41
+
42
+ PreAnalysis::~PreAnalysis()
43
+ {
44
+ for (auto& [func, wto] : funcToWTO)
45
+ delete wto;
46
+ }
47
+
48
+ void PreAnalysis::initWTO()
49
+ {
50
+ callGraphSCC->find();
51
+
52
+ for (auto it = callGraph->begin(); it != callGraph->end(); it++)
53
+ {
54
+ const FunObjVar *fun = it->second->getFunction();
55
+ if (fun->isDeclaration())
56
+ continue;
57
+
58
+ NodeID repNodeId = callGraphSCC->repNode(it->second->getId());
59
+ auto cgSCCNodes = callGraphSCC->subNodes(repNodeId);
60
+
61
+ bool isEntry = false;
62
+ if (it->second->getInEdges().empty())
63
+ isEntry = true;
64
+ for (auto inEdge: it->second->getInEdges())
65
+ {
66
+ NodeID srcNodeId = inEdge->getSrcID();
67
+ if (!cgSCCNodes.test(srcNodeId))
68
+ isEntry = true;
69
+ }
70
+
71
+ if (isEntry)
72
+ {
73
+ Set<const FunObjVar*> funcScc;
74
+ for (const auto& node: cgSCCNodes)
75
+ {
76
+ funcScc.insert(callGraph->getGNode(node)->getFunction());
77
+ }
78
+ ICFGWTO* iwto = new ICFGWTO(icfg->getFunEntryICFGNode(fun), funcScc);
79
+ iwto->init();
80
+ funcToWTO[it->second->getFunction()] = iwto;
81
+ }
82
+ }
83
+
84
+ }
@@ -878,10 +878,10 @@ int main(int argc, char** argv)
878
878
  LLVMModuleSet::getLLVMModuleSet()->buildSVFModule(moduleNameVec);
879
879
  SVFIRBuilder builder;
880
880
  SVFIR* pag = builder.build();
881
+ // Run Andersen's to resolve indirect calls, then update SVFIR with resolved targets.
882
+ // The Andersen singleton will be reused inside AbstractInterpretation::runOnModule().
881
883
  AndersenWaveDiff* ander = AndersenWaveDiff::createAndersenWaveDiff(pag);
882
- CallGraph* callgraph = ander->getCallGraph();
883
- builder.updateCallGraph(callgraph);
884
- pag->getICFG()->updateCallGraph(callgraph);
884
+ builder.updateCallGraph(ander->getCallGraph());
885
885
  AbstractInterpretation& ae = AbstractInterpretation::getAEInstance();
886
886
  if (Options::BufferOverflowCheck())
887
887
  ae.addDetector(std::make_unique<BufOverflowDetector>());