svf-tools 1.0.1257 → 1.0.1259

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.1257",
3
+ "version": "1.0.1259",
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": {
@@ -37,9 +37,9 @@
37
37
  #include "AE/Svfexe/AEStat.h"
38
38
  #include "SVFIR/SVFIR.h"
39
39
  #include "Util/SVFBugReport.h"
40
+ #include "Util/WorkList.h"
40
41
  #include "Graphs/SCC.h"
41
42
  #include "Graphs/CallGraph.h"
42
- #include <deque>
43
43
 
44
44
  namespace SVF
45
45
  {
@@ -94,6 +94,12 @@ public:
94
94
  WIDEN_NARROW
95
95
  };
96
96
 
97
+ enum AEFunEntryMode
98
+ {
99
+ MAIN,
100
+ NO_MAIN
101
+ };
102
+
97
103
  virtual void runOnModule();
98
104
 
99
105
  /// Destructor
@@ -106,7 +112,7 @@ public:
106
112
  void analyzeFromAllProgEntries();
107
113
 
108
114
  /// Get all entry point functions (functions without callers)
109
- std::deque<const FunObjVar*> collectProgEntryFuns();
115
+ FIFOWorkList<const FunObjVar*> collectProgEntryFuns();
110
116
 
111
117
  /// Factory: returns the singleton instance. The concrete class is
112
118
  /// chosen once, on first call, from `Options::AESparsity()`:
@@ -254,10 +260,10 @@ private:
254
260
  virtual void handleCallSite(const ICFGNode* node);
255
261
 
256
262
  /// Handle a WTO cycle (loop or recursive function) using widening/narrowing iteration
257
- virtual void handleLoopOrRecursion(const ICFGCycleWTO* cycle, const CallICFGNode* caller = nullptr);
263
+ virtual void handleLoopOrRecursion(const ICFGCycleWTO* cycle, const CallICFGNode* caller);
258
264
 
259
265
  /// Handle a function body via worklist-driven WTO traversal starting from funEntry
260
- void handleFunction(const ICFGNode* funEntry, const CallICFGNode* caller = nullptr);
266
+ void handleFunction(const ICFGNode* funEntry, const CallICFGNode* caller);
261
267
 
262
268
  /// Handle an ICFG node: execute statements; return true if state changed
263
269
  bool handleICFGNode(const ICFGNode* node);
@@ -241,6 +241,7 @@ public:
241
241
 
242
242
  // Abstract Execution
243
243
  static const OptionMap<u32_t> AESparsity;
244
+ static const OptionMap<u32_t> AEFunEntry;
244
245
  static const Option<u32_t> WidenDelay;
245
246
  /// recursion handling mode, Default: TOP
246
247
  static const OptionMap<u32_t> HandleRecur;
@@ -35,7 +35,6 @@
35
35
  #include "Graphs/CallGraph.h"
36
36
  #include "WPA/Andersen.h"
37
37
  #include <cmath>
38
- #include <deque>
39
38
  #include <memory>
40
39
 
41
40
  using namespace SVF;
@@ -118,11 +117,14 @@ AbstractInterpretation::~AbstractInterpretation()
118
117
  }
119
118
 
120
119
  /// Collect entry point functions for analysis.
121
- /// Entry points are functions without callers (no incoming edges in CallGraph).
122
- /// Uses a deque to allow efficient insertion at front for prioritizing main()
123
- std::deque<const FunObjVar*> AbstractInterpretation::collectProgEntryFuns()
120
+ /// In main mode, entry is main/svf.main. In no-main mode,
121
+ /// entries are SCCs with no external caller in the Andersen-resolved CallGraph.
122
+ FIFOWorkList<const FunObjVar*> AbstractInterpretation::collectProgEntryFuns()
124
123
  {
125
- std::deque<const FunObjVar*> entryFunctions;
124
+ FIFOWorkList<const FunObjVar*> entryFunctions;
125
+ const bool mainEntry = Options::AEFunEntry() == AEFunEntryMode::MAIN;
126
+ Set<NodeID> visitedEntrySCCs;
127
+ auto* callGraphSCC = preAnalysis->getCallGraphSCC();
126
128
 
127
129
  for (auto it = callGraph->begin(); it != callGraph->end(); ++it)
128
130
  {
@@ -133,39 +135,80 @@ std::deque<const FunObjVar*> AbstractInterpretation::collectProgEntryFuns()
133
135
  if (fun->isDeclaration())
134
136
  continue;
135
137
 
136
- // Entry points are functions without callers (no incoming edges)
137
- if (cgNode->getInEdges().empty())
138
+ if (mainEntry)
138
139
  {
139
- // If main exists, put it first for priority using deque's push_front
140
140
  if (SVFUtil::isProgEntryFunction(fun))
141
141
  {
142
- entryFunctions.push_front(fun);
142
+ entryFunctions.push(fun);
143
+ break;
143
144
  }
144
- else
145
+ }
146
+ else
147
+ {
148
+ NodeID repNodeId = callGraphSCC->repNode(cgNode->getId());
149
+ if (visitedEntrySCCs.count(repNodeId))
150
+ continue;
151
+
152
+ const NodeBS& cgSCCNodes = callGraphSCC->subNodes(repNodeId);
153
+ bool hasExternalCaller = false;
154
+ for (NodeID nodeId : cgSCCNodes)
145
155
  {
146
- entryFunctions.push_back(fun);
156
+ const CallGraphNode* sccNode = callGraph->getGNode(nodeId);
157
+ for (auto inEdge : sccNode->getInEdges())
158
+ {
159
+ if (!cgSCCNodes.test(inEdge->getSrcID()))
160
+ {
161
+ hasExternalCaller = true;
162
+ break;
163
+ }
164
+ }
165
+ if (hasExternalCaller)
166
+ break;
147
167
  }
168
+
169
+ if (hasExternalCaller)
170
+ continue;
171
+
172
+ visitedEntrySCCs.insert(repNodeId);
173
+ const FunObjVar* entryFun = fun;
174
+ for (NodeID nodeId : cgSCCNodes)
175
+ {
176
+ const FunObjVar* sccFun = callGraph->getGNode(nodeId)->getFunction();
177
+ if (SVFUtil::isProgEntryFunction(sccFun))
178
+ {
179
+ entryFun = sccFun;
180
+ break;
181
+ }
182
+ }
183
+ entryFunctions.push(entryFun);
148
184
  }
149
185
  }
150
186
 
187
+ if (mainEntry && entryFunctions.empty())
188
+ {
189
+ SVFUtil::errs() << SVFUtil::errMsg(
190
+ "AE -ae-fun-entry=main requires a program entry function, but main/svf.main was not found.\n");
191
+ assert(false && "No program entry function found for -ae-fun-entry=main");
192
+ abort();
193
+ }
194
+
151
195
  return entryFunctions;
152
196
  }
153
197
 
154
198
 
155
- /// Program entry - analyze from all entry points (multi-entry analysis is the default)
199
+ /// Program entry - entry policy is selected by -ae-fun-entry.
156
200
  void AbstractInterpretation::analyse()
157
201
  {
158
- // Always use multi-entry analysis from all entry points
159
202
  analyzeFromAllProgEntries();
160
203
  }
161
204
 
162
- /// Analyze all entry points (functions without callers) - for whole-program analysis.
205
+ /// Analyze the entry functions selected by collectProgEntryFuns().
163
206
  /// Abstract state is shared across entry points so that functions analyzed from
164
207
  /// earlier entries are not re-analyzed from scratch.
165
208
  void AbstractInterpretation::analyzeFromAllProgEntries()
166
209
  {
167
210
  // Collect all entry point functions
168
- std::deque<const FunObjVar*> entryFunctions = collectProgEntryFuns();
211
+ FIFOWorkList<const FunObjVar*> entryFunctions = collectProgEntryFuns();
169
212
 
170
213
  if (entryFunctions.empty())
171
214
  {
@@ -174,10 +217,13 @@ void AbstractInterpretation::analyzeFromAllProgEntries()
174
217
  }
175
218
  // handle Global ICFGNode of SVFModule
176
219
  handleGlobalNode();
177
- for (const FunObjVar* entryFun : entryFunctions)
220
+ const ICFGNode* globalNode = icfg->getGlobalICFGNode();
221
+ while (!entryFunctions.empty())
178
222
  {
223
+ const FunObjVar* entryFun = entryFunctions.pop();
179
224
  const ICFGNode* funEntry = icfg->getFunEntryICFGNode(entryFun);
180
- handleFunction(funEntry);
225
+ updateAbsState(funEntry, getAbsState(globalNode));
226
+ handleFunction(funEntry, nullptr);
181
227
  }
182
228
  }
183
229
 
@@ -443,7 +489,7 @@ static IntervalValue computeCmpConstraint(s32_t predicate, s64_t succ,
443
489
  }
444
490
 
445
491
  bool AbstractInterpretation::isCmpBranchEdgeFeasible(const IntraCFGEdge* edge,
446
- AbstractState& as)
492
+ AbstractState& as)
447
493
  {
448
494
  const ICFGNode* pred = edge->getSrcNode();
449
495
  s64_t succ = edge->getSuccessorCondValue();
@@ -489,7 +535,7 @@ bool AbstractInterpretation::isSwitchBranchEdgeFeasible(
489
535
  }
490
536
 
491
537
  void AbstractInterpretation::collectBranchRefinement(const IntraCFGEdge* edge,
492
- AbstractState& as)
538
+ AbstractState& as)
493
539
  {
494
540
  const SVFVar* cond = edge->getCondition();
495
541
  const ICFGNode* pred = edge->getSrcNode();
@@ -505,14 +551,15 @@ void AbstractInterpretation::collectBranchRefinement(const IntraCFGEdge* edge,
505
551
  s32_t predicate = cmpStmt->getPredicate();
506
552
 
507
553
  if (cmpStmt->getOpVarID(0) == IRGraph::NullPtr ||
508
- cmpStmt->getOpVarID(1) == IRGraph::NullPtr)
554
+ cmpStmt->getOpVarID(1) == IRGraph::NullPtr)
509
555
  {
510
556
  // p == NULL / p != NULL: no interval obj to refine.
511
557
  }
512
558
  else
513
559
  {
514
560
  AbstractValue opVal[2] = {getAbsValue(cmpStmt->getOpVar(0), pred),
515
- getAbsValue(cmpStmt->getOpVar(1), pred)};
561
+ getAbsValue(cmpStmt->getOpVar(1), pred)
562
+ };
516
563
 
517
564
  const bool hasIntervalCmp =
518
565
  opVal[0].isInterval() && opVal[1].isInterval();
@@ -543,8 +590,8 @@ void AbstractInterpretation::collectBranchRefinement(const IntraCFGEdge* edge,
543
590
  else
544
591
  {
545
592
  IntervalValue narrowed = computeCmpConstraint(
546
- predicate, succ, i == 0, opVal[i].getInterval(),
547
- opVal[other].getInterval());
593
+ predicate, succ, i == 0, opVal[i].getInterval(),
594
+ opVal[other].getInterval());
548
595
 
549
596
  if (narrowed.isTop())
550
597
  {
@@ -658,7 +705,7 @@ void AbstractInterpretation::recordBranchRefinement(
658
705
  }
659
706
 
660
707
  bool AbstractInterpretation::isBranchEdgeFeasible(const IntraCFGEdge* edge,
661
- AbstractState& as)
708
+ AbstractState& as)
662
709
  {
663
710
  const SVFVar* cmpVar = edge->getCondition();
664
711
  assert(!cmpVar->getInEdges().empty() && "branch condition has no defining edge?");
@@ -735,8 +782,7 @@ bool AbstractInterpretation::handleICFGNode(const ICFGNode* node)
735
782
  void AbstractInterpretation::handleFunction(const ICFGNode* funEntry, const CallICFGNode* caller)
736
783
  {
737
784
  auto it = preAnalysis->getFuncToWTO().find(funEntry->getFun());
738
- if (it == preAnalysis->getFuncToWTO().end())
739
- return;
785
+ assert(it != preAnalysis->getFuncToWTO().end() && "Missing WTO for function");
740
786
 
741
787
  // Push all top-level WTO components into the worklist in WTO order
742
788
  FIFOWorkList<const ICFGWTOComp*> worklist(it->second->getWTOComponents());
@@ -62,7 +62,7 @@ void FullSparseAbstractInterpretation::buildSVFG()
62
62
  // =====================================================================
63
63
 
64
64
  void FullSparseAbstractInterpretation::joinStates(AbstractState& dst,
65
- const AbstractState& src)
65
+ const AbstractState& src)
66
66
  {
67
67
  // Propagate GepObjVar entries along ICFG edges. Kill semantics
68
68
  // come from handleNode's as.store(addr, val) overwriting trace at
@@ -88,8 +88,8 @@ void FullSparseAbstractInterpretation::joinStates(AbstractState& dst,
88
88
  }
89
89
 
90
90
  void FullSparseAbstractInterpretation::storeValue(const ValVar* pointer,
91
- const AbstractValue& val,
92
- const ICFGNode* node)
91
+ const AbstractValue& val,
92
+ const ICFGNode* node)
93
93
  {
94
94
  // Clear branch refinement for every ObjVar this store overwrites.
95
95
  // A store redefines the ObjVar; the pre-store branch constraint
@@ -206,20 +206,20 @@ void FullSparseAbstractInterpretation::pullObjValueFlows(const ICFGNode* node)
206
206
  continue;
207
207
  }
208
208
  if (obj &&
209
- SemiSparseAbstractInterpretation::hasAbsValue(
210
- obj, srcICFG))
209
+ SemiSparseAbstractInterpretation::hasAbsValue(
210
+ obj, srcICFG))
211
211
  {
212
212
  AbstractValue cur;
213
213
  if (SemiSparseAbstractInterpretation::
214
214
  hasAbsValue(obj, node))
215
215
  {
216
216
  cur = SemiSparseAbstractInterpretation::
217
- getAbsValue(obj, node);
217
+ getAbsValue(obj, node);
218
218
  }
219
219
  cur.join_with(SemiSparseAbstractInterpretation::
220
- getAbsValue(obj, srcICFG));
220
+ getAbsValue(obj, srcICFG));
221
221
  SemiSparseAbstractInterpretation::
222
- updateAbsValue(obj, cur, node);
222
+ updateAbsValue(obj, cur, node);
223
223
  }
224
224
  }
225
225
  }
@@ -243,7 +243,7 @@ static bool hasRedefineToSameObj(const ICFGNode* node,
243
243
  for (const VFGNode* vfgNode : node->getVFGNodes())
244
244
  {
245
245
  if (SVFUtil::isa<StoreVFGNode>(vfgNode) &&
246
- vfgNode->getDefSVFVars().intersects(edge->getPointsTo()))
246
+ vfgNode->getDefSVFVars().intersects(edge->getPointsTo()))
247
247
  return true;
248
248
  }
249
249
 
@@ -298,7 +298,7 @@ bool FullSparseAbstractInterpretation::isIndirectSVFGEdgeFeasible(
298
298
  // normal analysis; here we only need caller-side reachability,
299
299
  // e.g. entry -> ret-site.
300
300
  if (const CallICFGNode* call =
301
- SVFUtil::dyn_cast<CallICFGNode>(cur))
301
+ SVFUtil::dyn_cast<CallICFGNode>(cur))
302
302
  {
303
303
  const ICFGNode* succ = call->getRetICFGNode();
304
304
  if (!succ || succ->getFun() != fun)
@@ -361,7 +361,7 @@ bool FullSparseAbstractInterpretation::isIndirectSVFGEdgeFeasible(
361
361
  }
362
362
 
363
363
  bool FullSparseAbstractInterpretation::isICFGPathFeasible(const ICFGNode* src,
364
- const ICFGNode* dst)
364
+ const ICFGNode* dst)
365
365
  {
366
366
  bool feasible = true;
367
367
  if (!src || !dst)
@@ -397,7 +397,7 @@ bool FullSparseAbstractInterpretation::isICFGPathFeasible(const ICFGNode* src,
397
397
  // normal analysis; here we only need caller-side reachability,
398
398
  // e.g. entry -> ret-site.
399
399
  if (const CallICFGNode* call =
400
- SVFUtil::dyn_cast<CallICFGNode>(cur))
400
+ SVFUtil::dyn_cast<CallICFGNode>(cur))
401
401
  {
402
402
  const ICFGNode* succ = call->getRetICFGNode();
403
403
  if (!succ || succ->getFun() != fun)
@@ -665,7 +665,7 @@ void SemiSparseAbstractInterpretation::updateAbsState(
665
665
  }
666
666
 
667
667
  void SemiSparseAbstractInterpretation::joinStates(AbstractState& dst,
668
- const AbstractState& src)
668
+ const AbstractState& src)
669
669
  {
670
670
  // ValVars live at def-sites in semi-sparse mode; they don't flow
671
671
  // through state merges. Iterate src's ObjVar (_addrToAbsVal) entries
@@ -697,7 +697,7 @@ const ICFGNode* SemiSparseAbstractInterpretation::getICFGNode(
697
697
  SVFUtil::isa<RetValPN>(var))
698
698
  {
699
699
  return SVFUtil::dyn_cast<CallICFGNode>(var->getICFGNode())
700
- ->getRetICFGNode();
700
+ ->getRetICFGNode();
701
701
  }
702
702
  // for other ValVars, use their def-site as the node to query abstract
703
703
  // value.
@@ -708,8 +708,8 @@ const ICFGNode* SemiSparseAbstractInterpretation::getICFGNode(
708
708
  }
709
709
 
710
710
  void SemiSparseAbstractInterpretation::updateAbsValue(const ValVar* var,
711
- const AbstractValue& val,
712
- const ICFGNode* node)
711
+ const AbstractValue& val,
712
+ const ICFGNode* node)
713
713
  {
714
714
  // Write to the var's def-site so getAbsValue stays consistent.
715
715
  const ICFGNode* defNode = var->getICFGNode();
@@ -724,7 +724,7 @@ const AbstractValue& SemiSparseAbstractInterpretation::getAbsValue(
724
724
  }
725
725
 
726
726
  bool SemiSparseAbstractInterpretation::hasAbsValue(const ValVar* var,
727
- const ICFGNode* node) const
727
+ const ICFGNode* node) const
728
728
  {
729
729
  return AbstractInterpretation::hasAbsValue(var, getICFGNode(var));
730
730
  }
@@ -799,6 +799,20 @@ const OptionMap<u32_t> Options::AESparsity(
799
799
  "Sparse abstract execution via SVFG."
800
800
  }
801
801
  });
802
+ const OptionMap<u32_t> Options::AEFunEntry(
803
+ "ae-fun-entry",
804
+ "Abstract execution function entry mode (Default: main)",
805
+ AbstractInterpretation::AEFunEntryMode::MAIN,
806
+ {
807
+ {
808
+ AbstractInterpretation::AEFunEntryMode::MAIN, "main",
809
+ "Analyze from the program entry function only."
810
+ },
811
+ {
812
+ AbstractInterpretation::AEFunEntryMode::NO_MAIN, "no-main",
813
+ "Analyze from every no-external-caller SCC after Andersen resolves the call graph."
814
+ }
815
+ });
802
816
  const Option<u32_t> Options::WidenDelay(
803
817
  "widen-delay", "Loop Widen Delay", 3);
804
818
  const OptionMap<u32_t> Options::HandleRecur(