svf-tools 1.0.1236 → 1.0.1237

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.
Files changed (127) hide show
  1. package/package.json +1 -1
  2. package/svf/include/AE/Core/AbstractState.h +1 -1
  3. package/svf/include/AE/Svfexe/AbstractInterpretation.h +29 -0
  4. package/svf/include/AE/Svfexe/AbstractStateManager.h +13 -0
  5. package/svf/include/AE/Svfexe/PreAnalysis.h +3 -3
  6. package/svf/lib/AE/Svfexe/AbstractInterpretation.cpp +107 -13
  7. package/svf/lib/AE/Svfexe/AbstractStateManager.cpp +66 -0
  8. package/svf/lib/AE/Svfexe/PreAnalysis.cpp +3 -3
  9. package/SVF-doxygen/doxygen.config +0 -2548
  10. package/SVF-doxygen/wiki/PAG.png +0 -0
  11. package/SVF-doxygen/wiki/andersen.png +0 -0
  12. package/SVF-doxygen/wiki/callgraph.png +0 -0
  13. package/SVF-doxygen/wiki/consG.png +0 -0
  14. package/SVF-doxygen/wiki/cpu2000-flto +0 -432
  15. package/SVF-doxygen/wiki/cpu2006-flto +0 -417
  16. package/SVF-doxygen/wiki/cpu2017-wllvm.cfg +0 -999
  17. package/SVF-doxygen/wiki/database.png +0 -0
  18. package/SVF-doxygen/wiki/framework.png +0 -0
  19. package/SVF-doxygen/wiki/help.png +0 -0
  20. package/SVF-doxygen/wiki/icfg.png +0 -0
  21. package/SVF-doxygen/wiki/mssa-cha.png +0 -0
  22. package/SVF-doxygen/wiki/pagedge.png +0 -0
  23. package/SVF-doxygen/wiki/pagnode.png +0 -0
  24. package/SVF-doxygen/wiki/pt.png +0 -0
  25. package/SVF-doxygen/wiki/setupcmake.png +0 -0
  26. package/SVF-doxygen/wiki/setupconfiguration.png +0 -0
  27. package/SVF-doxygen/wiki/setupdashboard.png +0 -0
  28. package/SVF-doxygen/wiki/setupdebug.png +0 -0
  29. package/SVF-doxygen/wiki/setupenv.png +0 -0
  30. package/SVF-doxygen/wiki/startup.png +0 -0
  31. package/SVF-doxygen/wiki/svf-stat.pdf +0 -0
  32. package/SVF-doxygen/wiki/svfg-framework.png +0 -0
  33. package/SVF-doxygen/wiki/svfg.png +0 -0
  34. package/SVF-doxygen/wiki/svfg_opt.png +0 -0
  35. package/SVF-doxygen/wiki/svfgedge-cha.png +0 -0
  36. package/SVF-doxygen/wiki/svfgnode-cha.png +0 -0
  37. package/SVF-doxygen/wiki/svfpic/README.md +0 -6
  38. package/SVF-doxygen/wiki/svfpic/ass-1debug1.png +0 -0
  39. package/SVF-doxygen/wiki/svfpic/ass-1debug2.png +0 -0
  40. package/SVF-doxygen/wiki/svfpic/build.jpg +0 -0
  41. package/SVF-doxygen/wiki/svfpic/cmd.png +0 -0
  42. package/SVF-doxygen/wiki/svfpic/connect1.jpg +0 -0
  43. package/SVF-doxygen/wiki/svfpic/connect2.png +0 -0
  44. package/SVF-doxygen/wiki/svfpic/connect3.png +0 -0
  45. package/SVF-doxygen/wiki/svfpic/connect4.jpg +0 -0
  46. package/SVF-doxygen/wiki/svfpic/connect5.jpg +0 -0
  47. package/SVF-doxygen/wiki/svfpic/connect6.png +0 -0
  48. package/SVF-doxygen/wiki/svfpic/connect7.jpg +0 -0
  49. package/SVF-doxygen/wiki/svfpic/continue.png +0 -0
  50. package/SVF-doxygen/wiki/svfpic/debug-new.png +0 -0
  51. package/SVF-doxygen/wiki/svfpic/debug-new2.png +0 -0
  52. package/SVF-doxygen/wiki/svfpic/debug1.jpeg +0 -0
  53. package/SVF-doxygen/wiki/svfpic/debug2.jpeg +0 -0
  54. package/SVF-doxygen/wiki/svfpic/debug3.png +0 -0
  55. package/SVF-doxygen/wiki/svfpic/debug4.png +0 -0
  56. package/SVF-doxygen/wiki/svfpic/debug5.jpeg +0 -0
  57. package/SVF-doxygen/wiki/svfpic/debug6.jpeg +0 -0
  58. package/SVF-doxygen/wiki/svfpic/docker_sys_requirement.png +0 -0
  59. package/SVF-doxygen/wiki/svfpic/docker_sys_requirements.png +0 -0
  60. package/SVF-doxygen/wiki/svfpic/dockerbuild.png +0 -0
  61. package/SVF-doxygen/wiki/svfpic/dockerbuild2.jpg +0 -0
  62. package/SVF-doxygen/wiki/svfpic/dockerbuild3.jpg +0 -0
  63. package/SVF-doxygen/wiki/svfpic/dockerbuild4.png +0 -0
  64. package/SVF-doxygen/wiki/svfpic/dockerbuild5.jpg +0 -0
  65. package/SVF-doxygen/wiki/svfpic/dockerbuildimage.png +0 -0
  66. package/SVF-doxygen/wiki/svfpic/dockercmd.png +0 -0
  67. package/SVF-doxygen/wiki/svfpic/dockercmd2.png +0 -0
  68. package/SVF-doxygen/wiki/svfpic/dockercontainer.png +0 -0
  69. package/SVF-doxygen/wiki/svfpic/dockerdb1.jpg +0 -0
  70. package/SVF-doxygen/wiki/svfpic/dockerdb10.jpeg +0 -0
  71. package/SVF-doxygen/wiki/svfpic/dockerdb2.jpg +0 -0
  72. package/SVF-doxygen/wiki/svfpic/dockerdb3.jpg +0 -0
  73. package/SVF-doxygen/wiki/svfpic/dockerdb4.jpg +0 -0
  74. package/SVF-doxygen/wiki/svfpic/dockerdb5.png +0 -0
  75. package/SVF-doxygen/wiki/svfpic/dockerdb6.jpeg +0 -0
  76. package/SVF-doxygen/wiki/svfpic/dockerdb7.png +0 -0
  77. package/SVF-doxygen/wiki/svfpic/dockerdb8.png +0 -0
  78. package/SVF-doxygen/wiki/svfpic/dockerdb9.jpeg +0 -0
  79. package/SVF-doxygen/wiki/svfpic/dockerfinshbuilt.png +0 -0
  80. package/SVF-doxygen/wiki/svfpic/dockerimage.png +0 -0
  81. package/SVF-doxygen/wiki/svfpic/dockernameImage.png +0 -0
  82. package/SVF-doxygen/wiki/svfpic/dockerpull.png +0 -0
  83. package/SVF-doxygen/wiki/svfpic/dockerpull2.png +0 -0
  84. package/SVF-doxygen/wiki/svfpic/download.jpg +0 -0
  85. package/SVF-doxygen/wiki/svfpic/extension1.jpeg +0 -0
  86. package/SVF-doxygen/wiki/svfpic/extension2.jpeg +0 -0
  87. package/SVF-doxygen/wiki/svfpic/graphviz.png +0 -0
  88. package/SVF-doxygen/wiki/svfpic/hellodb.png +0 -0
  89. package/SVF-doxygen/wiki/svfpic/hellodb2.png +0 -0
  90. package/SVF-doxygen/wiki/svfpic/hviz_0.png +0 -0
  91. package/SVF-doxygen/wiki/svfpic/hviz_1.png +0 -0
  92. package/SVF-doxygen/wiki/svfpic/hviz_2.png +0 -0
  93. package/SVF-doxygen/wiki/svfpic/installC:C++Ext.png +0 -0
  94. package/SVF-doxygen/wiki/svfpic/installCMakeExt.png +0 -0
  95. package/SVF-doxygen/wiki/svfpic/installRCext.png +0 -0
  96. package/SVF-doxygen/wiki/svfpic/installdockerext.png +0 -0
  97. package/SVF-doxygen/wiki/svfpic/launch1.png +0 -0
  98. package/SVF-doxygen/wiki/svfpic/openfile.png +0 -0
  99. package/SVF-doxygen/wiki/svfpic/pathfolder.png +0 -0
  100. package/SVF-doxygen/wiki/svfpic/restart.png +0 -0
  101. package/SVF-doxygen/wiki/svfpic/rundocker.png +0 -0
  102. package/SVF-doxygen/wiki/svfpic/runinCLI.png +0 -0
  103. package/SVF-doxygen/wiki/svfpic/screen.png +0 -0
  104. package/SVF-doxygen/wiki/svfpic/settings1.jpg +0 -0
  105. package/SVF-doxygen/wiki/svfpic/settings2.jpg +0 -0
  106. package/SVF-doxygen/wiki/svfpic/settings3.jpg +0 -0
  107. package/SVF-doxygen/wiki/svfpic/shortlists.png +0 -0
  108. package/SVF-doxygen/wiki/svfpic/start.png +0 -0
  109. package/SVF-doxygen/wiki/svfpic/start1.png +0 -0
  110. package/SVF-doxygen/wiki/svfpic/update0.png +0 -0
  111. package/SVF-doxygen/wiki/svfpic/verify_docker.png +0 -0
  112. package/SVF-doxygen/wiki/svfpic/vs_entry_window.png +0 -0
  113. package/SVF-doxygen/wiki/svfpic/wsl.png +0 -0
  114. package/SVF-doxygen/wiki/svfpic/wsl_1.png +0 -0
  115. package/SVF-doxygen/wiki/svfpic/wsl_2.png +0 -0
  116. package/SVF-doxygen/wiki/svfpic/wsl_3.png +0 -0
  117. package/SVF-doxygen/wiki/tools.png +0 -0
  118. package/SVF-doxygen/wiki/users.png +0 -0
  119. package/SVF-doxygen/wiki/vm1.png +0 -0
  120. package/SVF-doxygen/wiki/vm2.png +0 -0
  121. package/SVF-doxygen/wiki/vm3.png +0 -0
  122. package/SVF-doxygen/wiki/vm4.png +0 -0
  123. package/SVF-doxygen/wiki/vm5.png +0 -0
  124. package/SVF-doxygen/wiki/vscode_build_tasks.png +0 -0
  125. package/SVF-doxygen/wiki/vscode_cpp_extension.png +0 -0
  126. package/SVF-doxygen/wiki/vscode_debug_list.png +0 -0
  127. package/SVF-doxygen/wiki/vscode_dir_structure.png +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svf-tools",
3
- "version": "1.0.1236",
3
+ "version": "1.0.1237",
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": {
@@ -352,7 +352,7 @@ public:
352
352
  /// freed addresses intact. Used when building a cycle snapshot so the
353
353
  /// ValVar set is controlled by the caller rather than whatever was
354
354
  /// cached at the seed node.
355
- void clearVars()
355
+ void clearValVars()
356
356
  {
357
357
  _varToAbsVal.clear();
358
358
  }
@@ -149,6 +149,11 @@ public:
149
149
  svfStateMgr->updateAbstractState(node, state);
150
150
  }
151
151
 
152
+ inline bool hasAbsValue(const SVFVar* var, const ICFGNode* node)
153
+ {
154
+ return svfStateMgr->hasAbstractValue(var, node);
155
+ }
156
+
152
157
  inline const AbstractValue& getAbsValue(const SVFVar* var, const ICFGNode* node)
153
158
  {
154
159
  return svfStateMgr->getAbstractValue(var, node);
@@ -180,6 +185,30 @@ private:
180
185
  /// Handle a WTO cycle (loop or recursive function) using widening/narrowing iteration
181
186
  virtual void handleLoopOrRecursion(const ICFGCycleWTO* cycle, const CallICFGNode* caller = nullptr);
182
187
 
188
+ // ---- Semi-sparse cycle helpers ----
189
+ // ValVars whose def-site is inside the cycle but NOT cycle_head do not
190
+ // flow through cycle_head's merge in semi-sparse mode, so the around-merge
191
+ // widening cannot observe them. getFullCycleHeadState pulls these ValVars
192
+ // into a single AbstractState snapshot so widen/narrow can treat ValVars
193
+ // and ObjVars uniformly; after widen/narrow we scatter the ValVars back
194
+ // to their def-sites.
195
+
196
+ /// Build a full cycle-head AbstractState: the ObjVars currently at
197
+ /// cycle_head combined with every cycle ValVar pulled from its
198
+ /// def-site. Skips ValVars without a stored value to avoid the
199
+ /// top-fallback contamination. In dense mode this is equivalent to
200
+ /// trace[cycle_head] since ValVars already live there.
201
+ AbstractState getFullCycleHeadState(const ICFGCycleWTO* cycle);
202
+
203
+ /// Widen prev with cur; write the widened state to trace[cycle_head]
204
+ /// and scatter its ValVars back to their def-sites. Returns true
205
+ /// when the widened result equals prev (fixpoint).
206
+ bool widenCycleState(const AbstractState& prev, const AbstractState& cur,
207
+ const ICFGCycleWTO* cycle);
208
+ /// Narrow prev with cur; write the narrowed state back and scatter.
209
+ bool narrowCycleState(const AbstractState& prev, const AbstractState& cur,
210
+ const ICFGCycleWTO* cycle);
211
+
183
212
  /// Handle a function body via worklist-driven WTO traversal starting from funEntry
184
213
  void handleFunction(const ICFGNode* funEntry, const CallICFGNode* caller = nullptr);
185
214
 
@@ -66,6 +66,19 @@ public:
66
66
  /// Dispatch to ValVar or ObjVar overload (checks ObjVar first due to inheritance).
67
67
  const AbstractValue& getAbstractValue(const SVFVar* var, const ICFGNode* node);
68
68
 
69
+ /// Check whether a ValVar has a real stored value reachable by
70
+ /// getAbstractValue. Unlike getAbstractValue, this is side-effect free
71
+ /// and does NOT treat the final top-fallback as "present" — so callers
72
+ /// that plan to write the fetched value back (e.g. cycle widen/narrow)
73
+ /// can distinguish a genuine stored value from the top sentinel.
74
+ bool hasAbstractValue(const ValVar* var, const ICFGNode* node) const;
75
+
76
+ /// Check whether an ObjVar has a stored value at node.
77
+ bool hasAbstractValue(const ObjVar* var, const ICFGNode* node) const;
78
+
79
+ /// Dispatch to ValVar or ObjVar overload.
80
+ bool hasAbstractValue(const SVFVar* var, const ICFGNode* node) const;
81
+
69
82
  /// Write a top-level variable's abstract value into abstractTrace[node].
70
83
  void updateAbstractValue(const ValVar* var, const AbstractValue& val, const ICFGNode* node);
71
84
 
@@ -80,10 +80,10 @@ public:
80
80
 
81
81
  /// Look up the ValVar id set of a WTO cycle. Returns nullptr if the
82
82
  /// cycle is unknown (e.g. dense mode, where the map is never built).
83
- const Set<NodeID>* getCycleValVars(const ICFGCycleWTO* cycle) const
83
+ const Set<const ValVar*> getCycleValVars(const ICFGCycleWTO* cycle) const
84
84
  {
85
85
  auto it = cycleToValVars.find(cycle);
86
- return it == cycleToValVars.end() ? nullptr : &it->second;
86
+ return it == cycleToValVars.end() ? Set<const ValVar*>() : it->second;
87
87
  }
88
88
 
89
89
  private:
@@ -98,7 +98,7 @@ private:
98
98
  /// Pre-computed (semi-sparse only) map from a WTO cycle to the IDs of
99
99
  /// every ValVar whose def-site is inside that cycle, including all
100
100
  /// nested sub-cycles. Empty in dense mode.
101
- Map<const ICFGCycleWTO*, Set<NodeID>> cycleToValVars;
101
+ Map<const ICFGCycleWTO*, Set<const ValVar*>> cycleToValVars;
102
102
  };
103
103
 
104
104
  } // End namespace SVF
@@ -205,6 +205,7 @@ bool AbstractInterpretation::mergeStatesFromPredecessors(const ICFGNode* node)
205
205
  {
206
206
  // Collect all feasible predecessor states, then merge at the end.
207
207
  AbstractState merged;
208
+ bool hasFeasiblePred = false;
208
209
 
209
210
  for (auto& edge : node->getInEdges())
210
211
  {
@@ -218,16 +219,21 @@ bool AbstractInterpretation::mergeStatesFromPredecessors(const ICFGNode* node)
218
219
  {
219
220
  AbstractState predState = getAbsState(pred);
220
221
  if (isBranchFeasible(intraCfgEdge, predState))
222
+ {
221
223
  merged.joinWith(predState);
224
+ hasFeasiblePred = true;
225
+ }
222
226
  }
223
227
  else
224
228
  {
225
229
  merged.joinWith(getAbsState(pred));
230
+ hasFeasiblePred = true;
226
231
  }
227
232
  }
228
233
  else if (SVFUtil::isa<CallCFGEdge>(edge))
229
234
  {
230
235
  merged.joinWith(getAbsState(pred));
236
+ hasFeasiblePred = true;
231
237
  }
232
238
  else if (SVFUtil::isa<RetCFGEdge>(edge))
233
239
  {
@@ -235,6 +241,7 @@ bool AbstractInterpretation::mergeStatesFromPredecessors(const ICFGNode* node)
235
241
  {
236
242
  case TOP:
237
243
  merged.joinWith(getAbsState(pred));
244
+ hasFeasiblePred = true;
238
245
  break;
239
246
  case WIDEN_ONLY:
240
247
  case WIDEN_NARROW:
@@ -242,14 +249,17 @@ bool AbstractInterpretation::mergeStatesFromPredecessors(const ICFGNode* node)
242
249
  const RetICFGNode* returnSite = SVFUtil::dyn_cast<RetICFGNode>(node);
243
250
  const CallICFGNode* callSite = returnSite->getCallICFGNode();
244
251
  if (hasAbsState(callSite))
252
+ {
245
253
  merged.joinWith(getAbsState(pred));
254
+ hasFeasiblePred = true;
255
+ }
246
256
  break;
247
257
  }
248
258
  }
249
259
  }
250
260
  }
251
261
 
252
- if (merged.getVarToVal().empty() && merged.getLocToVal().empty())
262
+ if (!hasFeasiblePred)
253
263
  return false;
254
264
 
255
265
  updateAbsState(node, merged);
@@ -859,6 +869,96 @@ void AbstractInterpretation::handleFunCall(const CallICFGNode *callNode)
859
869
  /// int factorial(int n) { return n <= 1 ? 1 : n * factorial(n-1); }
860
870
  /// factorial(5) -> returns [10000, 10000] (precise after narrowing)
861
871
 
872
+ // ---------------------------------------------------------------------------
873
+ // Semi-sparse cycle helpers
874
+ // ---------------------------------------------------------------------------
875
+ //
876
+ // In semi-sparse mode, ValVars live at their def-sites and do not flow
877
+ // through the cycle-head merge. The around-merge widening at cycle_head
878
+ // therefore cannot observe ValVar growth across iterations (e.g. an
879
+ // ArgValVar that a recursive CallPE keeps overwriting at the FunEntry).
880
+ //
881
+ // To fix that, handleLoopOrRecursion runs an extra cross-iter widening on
882
+ // a snapshot that pulls every cycle ValVar into cycle_head's state. The set
883
+ // of ValVar IDs per cycle is precomputed once after PreAnalysis::initWTO()
884
+ // (initCycleValVars), bottom-up so nested cycles are handled before their
885
+ // enclosing cycle.
886
+
887
+ // --- Cycle state helpers (dense/sparse unified) ---
888
+
889
+ AbstractState AbstractInterpretation::getFullCycleHeadState(const ICFGCycleWTO* cycle)
890
+ {
891
+ const ICFGNode* cycle_head = cycle->head()->getICFGNode();
892
+ AbstractState snap;
893
+ if (hasAbsState(cycle_head))
894
+ snap = getAbsState(cycle_head);
895
+
896
+ if (Options::AESparsity() == AESparsity::SemiSparse)
897
+ {
898
+ const Set<const ValVar*>& valVars = preAnalysis->getCycleValVars(cycle);
899
+ if (valVars.empty())
900
+ return snap; // dense path / no cycle ValVars: snap is already complete
901
+
902
+ // Semi-sparse: drop any stale ValVar entries cached at cycle_head and
903
+ // pull each cycle ValVar from its def-site. ValVars without a stored
904
+ // value are skipped to avoid the top-fallback contamination.
905
+ snap.clearValVars();
906
+ for (const ValVar* v : valVars)
907
+ {
908
+ const ICFGNode* defSite = v->getICFGNode();
909
+ if (!defSite || !hasAbsValue(v, defSite)) continue;
910
+ snap[v->getId()] = getAbsValue(v, defSite);
911
+ }
912
+ return snap;
913
+ }
914
+ else
915
+ {
916
+ return snap;
917
+ }
918
+ }
919
+
920
+
921
+ bool AbstractInterpretation::widenCycleState(
922
+ const AbstractState& prev, const AbstractState& cur, const ICFGCycleWTO* cycle)
923
+ {
924
+ AbstractState prev_copy = prev;
925
+ AbstractState next = prev_copy.widening(cur);
926
+ // Always write back (even at fixpoint) so cycle_head's trace holds the
927
+ // widened state for the upcoming narrowing phase.
928
+ const ICFGNode* cycle_head = cycle->head()->getICFGNode();
929
+ svfStateMgr->getTrace()[cycle_head] = next;
930
+ if (Options::AESparsity() == AESparsity::SemiSparse)
931
+ {
932
+ for (const auto& [id, val] : next.getVarToVal())
933
+ {
934
+ updateAbsValue(svfir->getSVFVar(id), val, cycle_head);
935
+ }
936
+ }
937
+ return next == prev;
938
+ }
939
+
940
+ bool AbstractInterpretation::narrowCycleState(
941
+ const AbstractState& prev, const AbstractState& cur, const ICFGCycleWTO* cycle)
942
+ {
943
+ const ICFGNode* cycle_head = cycle->head()->getICFGNode();
944
+ if (!shouldApplyNarrowing(cycle_head->getFun()))
945
+ return true;
946
+ AbstractState prev_copy = prev;
947
+ AbstractState next = prev_copy.narrowing(cur);
948
+ if (next == prev)
949
+ return true; // fixpoint
950
+ svfStateMgr->getTrace()[cycle_head] = next;
951
+ if (Options::AESparsity() == AESparsity::SemiSparse)
952
+ {
953
+ for (const auto& [id, val] : next.getVarToVal())
954
+ {
955
+ updateAbsValue(svfir->getSVFVar(id), val, cycle_head);
956
+ }
957
+ }
958
+ return false;
959
+ }
960
+
961
+
862
962
  void AbstractInterpretation::handleLoopOrRecursion(const ICFGCycleWTO* cycle, const CallICFGNode* caller)
863
963
  {
864
964
  const ICFGNode* cycle_head = cycle->head()->getICFGNode();
@@ -874,35 +974,29 @@ void AbstractInterpretation::handleLoopOrRecursion(const ICFGCycleWTO* cycle, co
874
974
  // Iterate until fixpoint with widening/narrowing on the cycle head.
875
975
  bool increasing = true;
876
976
  u32_t widen_delay = Options::WidenDelay();
877
- auto& abstractTrace = svfStateMgr->getTrace();
878
977
  for (u32_t cur_iter = 0;; cur_iter++)
879
978
  {
880
979
  if (cur_iter >= widen_delay)
881
980
  {
882
- // Save state before processing head
883
- AbstractState prev_head_state = abstractTrace[cycle_head];
981
+ // getFullCycleHeadState handles dense (returns trace[cycle_head])
982
+ // and semi-sparse (collects ValVars from def-sites) uniformly.
983
+ AbstractState prev = getFullCycleHeadState(cycle);
884
984
 
885
- // Process cycle head: merge from predecessors, then execute statements
886
985
  if (mergeStatesFromPredecessors(cycle_head))
887
986
  handleICFGNode(cycle_head);
888
- AbstractState cur_head_state = abstractTrace[cycle_head];
987
+ AbstractState cur = getFullCycleHeadState(cycle);
889
988
 
890
989
  if (increasing)
891
990
  {
892
- abstractTrace[cycle_head] = prev_head_state.widening(cur_head_state);
893
- if (abstractTrace[cycle_head] == prev_head_state)
991
+ if (widenCycleState(prev, cur, cycle))
894
992
  {
895
- // Widening fixpoint reached; switch to narrowing phase.
896
993
  increasing = false;
897
994
  continue;
898
995
  }
899
996
  }
900
997
  else
901
998
  {
902
- if (!shouldApplyNarrowing(cycle_head->getFun()))
903
- break;
904
- abstractTrace[cycle_head] = prev_head_state.narrowing(cur_head_state);
905
- if (abstractTrace[cycle_head] == prev_head_state)
999
+ if (narrowCycleState(prev, cur, cycle))
906
1000
  break;
907
1001
  }
908
1002
  }
@@ -173,6 +173,71 @@ const AbstractValue& AbstractStateManager::getAbstractValue(const SVFVar* var, c
173
173
  abort();
174
174
  }
175
175
 
176
+ // ===----------------------------------------------------------------------===//
177
+ // hasAbstractValue — side-effect-free existence check
178
+ //
179
+ // Mirrors the lookup chain in getAbstractValue but stops short of the
180
+ // top-fallback. Returns false when getAbstractValue would only be able
181
+ // to return top as a default.
182
+ // ===----------------------------------------------------------------------===//
183
+
184
+ bool AbstractStateManager::hasAbstractValue(const ValVar* var, const ICFGNode* node) const
185
+ {
186
+ // Constants are always "present" (their value is intrinsic).
187
+ if (SVFUtil::isa<ConstIntValVar>(var) || SVFUtil::isa<ConstFPValVar>(var) ||
188
+ SVFUtil::isa<ConstNullPtrValVar>(var) || SVFUtil::isa<ConstDataValVar>(var))
189
+ return true;
190
+
191
+ u32_t id = var->getId();
192
+ bool semiSparse = Options::AESparsity() == AbstractInterpretation::AESparsity::SemiSparse;
193
+
194
+ // Dense mode: stored at the current node.
195
+ if (!semiSparse)
196
+ {
197
+ auto it = abstractTrace.find(node);
198
+ if (it != abstractTrace.end() &&
199
+ (it->second.inVarToValTable(id) || it->second.inVarToAddrsTable(id)))
200
+ return true;
201
+ }
202
+
203
+ // Semi-sparse (and dense fall-through): check the def-site.
204
+ const ICFGNode* defNode = var->getICFGNode();
205
+ if (defNode)
206
+ {
207
+ auto it = abstractTrace.find(defNode);
208
+ if (it != abstractTrace.end() && it->second.getVarToVal().count(id))
209
+ return true;
210
+
211
+ // Fallback for call-result ValVars: value lives at the RetICFGNode.
212
+ if (const CallICFGNode* callNode = SVFUtil::dyn_cast<CallICFGNode>(defNode))
213
+ {
214
+ const RetICFGNode* retNode = callNode->getRetICFGNode();
215
+ auto rit = abstractTrace.find(retNode);
216
+ if (rit != abstractTrace.end() && rit->second.getVarToVal().count(id))
217
+ return true;
218
+ }
219
+ }
220
+ return false;
221
+ }
222
+
223
+ bool AbstractStateManager::hasAbstractValue(const ObjVar* var, const ICFGNode* node) const
224
+ {
225
+ auto it = abstractTrace.find(node);
226
+ if (it == abstractTrace.end())
227
+ return false;
228
+ u32_t objId = var->getId();
229
+ return it->second.getLocToVal().count(objId) != 0;
230
+ }
231
+
232
+ bool AbstractStateManager::hasAbstractValue(const SVFVar* var, const ICFGNode* node) const
233
+ {
234
+ if (const ObjVar* objVar = SVFUtil::dyn_cast<ObjVar>(var))
235
+ return hasAbstractValue(objVar, node);
236
+ if (const ValVar* valVar = SVFUtil::dyn_cast<ValVar>(var))
237
+ return hasAbstractValue(valVar, node);
238
+ return false;
239
+ }
240
+
176
241
  // ===----------------------------------------------------------------------===//
177
242
  // Update Abstract Value
178
243
  // ===----------------------------------------------------------------------===//
@@ -520,3 +585,4 @@ const ICFGNode* AbstractStateManager::getDefSiteOfObjVar(const ObjVar* obj, cons
520
585
  return edge->getSrcNode();
521
586
  return nullptr;
522
587
  }
588
+
@@ -129,7 +129,7 @@ void PreAnalysis::initCycleValVars()
129
129
  // map when we reach their enclosing cycle.
130
130
  for (const ICFGCycleWTO* cycle : cycles)
131
131
  {
132
- Set<NodeID>& out = cycleToValVars[cycle];
132
+ Set<const ValVar*>& out = cycleToValVars[cycle];
133
133
 
134
134
  // Gather every ICFG node in this cycle (head + body singletons).
135
135
  // For nested sub-cycles, merge their already-computed sets instead.
@@ -154,7 +154,7 @@ void PreAnalysis::initCycleValVars()
154
154
  else if (const MultiOpndStmt* m = SVFUtil::dyn_cast<MultiOpndStmt>(stmt))
155
155
  lhs = m->getRes();
156
156
  if (lhs)
157
- out.insert(lhs->getId());
157
+ out.insert(lhs);
158
158
  }
159
159
  // FunEntryICFGNode owns ArgValVars (formal parameters) that have
160
160
  // no defining stmt at the entry — the CallPE lives on the caller
@@ -164,7 +164,7 @@ void PreAnalysis::initCycleValVars()
164
164
  {
165
165
  for (const SVFVar* fp : fe->getFormalParms())
166
166
  if (const ValVar* v = SVFUtil::dyn_cast<ValVar>(fp))
167
- out.insert(v->getId());
167
+ out.insert(v);
168
168
  }
169
169
  }
170
170
  }