svf-tools 1.0.1223 → 1.0.1225
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 +1 -1
- package/svf/include/AE/Svfexe/AbstractInterpretation.h +5 -4
- package/svf/lib/AE/Svfexe/AbstractInterpretation.cpp +90 -205
- package/SVF-doxygen/doxygen.config +0 -2548
- package/SVF-doxygen/wiki/PAG.png +0 -0
- package/SVF-doxygen/wiki/andersen.png +0 -0
- package/SVF-doxygen/wiki/callgraph.png +0 -0
- package/SVF-doxygen/wiki/consG.png +0 -0
- package/SVF-doxygen/wiki/cpu2000-flto +0 -432
- package/SVF-doxygen/wiki/cpu2006-flto +0 -417
- package/SVF-doxygen/wiki/cpu2017-wllvm.cfg +0 -999
- package/SVF-doxygen/wiki/database.png +0 -0
- package/SVF-doxygen/wiki/framework.png +0 -0
- package/SVF-doxygen/wiki/help.png +0 -0
- package/SVF-doxygen/wiki/icfg.png +0 -0
- package/SVF-doxygen/wiki/mssa-cha.png +0 -0
- package/SVF-doxygen/wiki/pagedge.png +0 -0
- package/SVF-doxygen/wiki/pagnode.png +0 -0
- package/SVF-doxygen/wiki/pt.png +0 -0
- package/SVF-doxygen/wiki/setupcmake.png +0 -0
- package/SVF-doxygen/wiki/setupconfiguration.png +0 -0
- package/SVF-doxygen/wiki/setupdashboard.png +0 -0
- package/SVF-doxygen/wiki/setupdebug.png +0 -0
- package/SVF-doxygen/wiki/setupenv.png +0 -0
- package/SVF-doxygen/wiki/startup.png +0 -0
- package/SVF-doxygen/wiki/svf-stat.pdf +0 -0
- package/SVF-doxygen/wiki/svfg-framework.png +0 -0
- package/SVF-doxygen/wiki/svfg.png +0 -0
- package/SVF-doxygen/wiki/svfg_opt.png +0 -0
- package/SVF-doxygen/wiki/svfgedge-cha.png +0 -0
- package/SVF-doxygen/wiki/svfgnode-cha.png +0 -0
- package/SVF-doxygen/wiki/svfpic/README.md +0 -6
- package/SVF-doxygen/wiki/svfpic/ass-1debug1.png +0 -0
- package/SVF-doxygen/wiki/svfpic/ass-1debug2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/build.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/cmd.png +0 -0
- package/SVF-doxygen/wiki/svfpic/connect1.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/connect2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/connect3.png +0 -0
- package/SVF-doxygen/wiki/svfpic/connect4.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/connect5.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/connect6.png +0 -0
- package/SVF-doxygen/wiki/svfpic/connect7.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/continue.png +0 -0
- package/SVF-doxygen/wiki/svfpic/debug-new.png +0 -0
- package/SVF-doxygen/wiki/svfpic/debug-new2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/debug1.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/debug2.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/debug3.png +0 -0
- package/SVF-doxygen/wiki/svfpic/debug4.png +0 -0
- package/SVF-doxygen/wiki/svfpic/debug5.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/debug6.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/docker_sys_requirement.png +0 -0
- package/SVF-doxygen/wiki/svfpic/docker_sys_requirements.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerbuild.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerbuild2.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerbuild3.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerbuild4.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerbuild5.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerbuildimage.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockercmd.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockercmd2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockercontainer.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb1.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb10.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb2.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb3.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb4.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb5.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb6.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb7.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb8.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerdb9.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerfinshbuilt.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerimage.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockernameImage.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerpull.png +0 -0
- package/SVF-doxygen/wiki/svfpic/dockerpull2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/download.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/extension1.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/extension2.jpeg +0 -0
- package/SVF-doxygen/wiki/svfpic/graphviz.png +0 -0
- package/SVF-doxygen/wiki/svfpic/hellodb.png +0 -0
- package/SVF-doxygen/wiki/svfpic/hellodb2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/hviz_0.png +0 -0
- package/SVF-doxygen/wiki/svfpic/hviz_1.png +0 -0
- package/SVF-doxygen/wiki/svfpic/hviz_2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/installC:C++Ext.png +0 -0
- package/SVF-doxygen/wiki/svfpic/installCMakeExt.png +0 -0
- package/SVF-doxygen/wiki/svfpic/installRCext.png +0 -0
- package/SVF-doxygen/wiki/svfpic/installdockerext.png +0 -0
- package/SVF-doxygen/wiki/svfpic/launch1.png +0 -0
- package/SVF-doxygen/wiki/svfpic/openfile.png +0 -0
- package/SVF-doxygen/wiki/svfpic/pathfolder.png +0 -0
- package/SVF-doxygen/wiki/svfpic/restart.png +0 -0
- package/SVF-doxygen/wiki/svfpic/rundocker.png +0 -0
- package/SVF-doxygen/wiki/svfpic/runinCLI.png +0 -0
- package/SVF-doxygen/wiki/svfpic/screen.png +0 -0
- package/SVF-doxygen/wiki/svfpic/settings1.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/settings2.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/settings3.jpg +0 -0
- package/SVF-doxygen/wiki/svfpic/shortlists.png +0 -0
- package/SVF-doxygen/wiki/svfpic/start.png +0 -0
- package/SVF-doxygen/wiki/svfpic/start1.png +0 -0
- package/SVF-doxygen/wiki/svfpic/update0.png +0 -0
- package/SVF-doxygen/wiki/svfpic/verify_docker.png +0 -0
- package/SVF-doxygen/wiki/svfpic/vs_entry_window.png +0 -0
- package/SVF-doxygen/wiki/svfpic/wsl.png +0 -0
- package/SVF-doxygen/wiki/svfpic/wsl_1.png +0 -0
- package/SVF-doxygen/wiki/svfpic/wsl_2.png +0 -0
- package/SVF-doxygen/wiki/svfpic/wsl_3.png +0 -0
- package/SVF-doxygen/wiki/tools.png +0 -0
- package/SVF-doxygen/wiki/users.png +0 -0
- package/SVF-doxygen/wiki/vm1.png +0 -0
- package/SVF-doxygen/wiki/vm2.png +0 -0
- package/SVF-doxygen/wiki/vm3.png +0 -0
- package/SVF-doxygen/wiki/vm4.png +0 -0
- package/SVF-doxygen/wiki/vm5.png +0 -0
- package/SVF-doxygen/wiki/vscode_build_tasks.png +0 -0
- package/SVF-doxygen/wiki/vscode_cpp_extension.png +0 -0
- package/SVF-doxygen/wiki/vscode_debug_list.png +0 -0
- 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.
|
|
3
|
+
"version": "1.0.1225",
|
|
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": {
|
|
@@ -156,9 +156,10 @@ private:
|
|
|
156
156
|
/// Initialize abstract state for the global ICFG node and process global statements
|
|
157
157
|
virtual void handleGlobalNode();
|
|
158
158
|
|
|
159
|
-
///
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
/// Pull-based state merge: read abstractTrace[pred] for each predecessor,
|
|
160
|
+
/// apply branch refinement for conditional IntraCFGEdges, and join into
|
|
161
|
+
/// abstractTrace[node]. Returns true if at least one predecessor had state.
|
|
162
|
+
bool mergeStatesFromPredecessors(const ICFGNode* node);
|
|
162
163
|
|
|
163
164
|
/// Check if the branch on intraEdge is feasible under abstract state as
|
|
164
165
|
bool isBranchFeasible(const IntraCFGEdge* intraEdge, AbstractState& as);
|
|
@@ -242,7 +243,7 @@ private:
|
|
|
242
243
|
// there data should be shared with subclasses
|
|
243
244
|
Map<std::string, std::function<void(const CallICFGNode*)>> func_map;
|
|
244
245
|
|
|
245
|
-
Map<const ICFGNode*, AbstractState> abstractTrace; // abstract states for nodes
|
|
246
|
+
Map<const ICFGNode*, AbstractState> abstractTrace; // abstract states for nodes
|
|
246
247
|
Set<const ICFGNode*> allAnalyzedNodes; // All nodes ever analyzed (across all entry points)
|
|
247
248
|
std::string moduleName;
|
|
248
249
|
|
|
@@ -286,61 +286,67 @@ void AbstractInterpretation::handleGlobalNode()
|
|
|
286
286
|
AddressValue(BlackHoleObjAddr);
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
-
///
|
|
290
|
-
///
|
|
291
|
-
///
|
|
292
|
-
///
|
|
293
|
-
|
|
294
|
-
/// If withinSet is non-null, only propagate to successors contained in that set.
|
|
295
|
-
/// This is used during cycle iteration to avoid propagating to nodes outside the
|
|
296
|
-
/// cycle, which would cause stale accumulation and lose narrowing precision.
|
|
297
|
-
/// Additionally, when withinSet is provided and a RetCFGEdge target is within the set,
|
|
298
|
-
/// the state is also propagated along that edge. This handles the FunExit -> RetNode
|
|
299
|
-
/// path inside recursive function cycles, where the recursive call is skipped and
|
|
300
|
-
/// the RetCFGEdge effectively acts as intra-procedural control flow.
|
|
301
|
-
void AbstractInterpretation::propagateToSuccessor(const ICFGNode* node,
|
|
302
|
-
const Set<const ICFGNode*>* withinSet)
|
|
289
|
+
/// Pull-based state merge: for each predecessor that has an abstract state,
|
|
290
|
+
/// copy its state, apply branch refinement for conditional IntraCFGEdges,
|
|
291
|
+
/// and join all feasible states into abstractTrace[node].
|
|
292
|
+
/// Returns true if at least one predecessor contributed state.
|
|
293
|
+
bool AbstractInterpretation::mergeStatesFromPredecessors(const ICFGNode* node)
|
|
303
294
|
{
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
for (auto& edge : node->getOutEdges())
|
|
295
|
+
std::vector<AbstractState> workList;
|
|
296
|
+
for (auto& edge : node->getInEdges())
|
|
308
297
|
{
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
const ICFGNode* dst = intraEdge->getDstNode();
|
|
313
|
-
// If a filter set is provided, skip successors not in the set
|
|
314
|
-
if (withinSet && withinSet->find(dst) == withinSet->end())
|
|
315
|
-
continue;
|
|
298
|
+
const ICFGNode* pred = edge->getSrcNode();
|
|
299
|
+
if (abstractTrace.find(pred) == abstractTrace.end())
|
|
300
|
+
continue;
|
|
316
301
|
|
|
317
|
-
|
|
318
|
-
|
|
302
|
+
if (const IntraCFGEdge* intraCfgEdge = SVFUtil::dyn_cast<IntraCFGEdge>(edge))
|
|
303
|
+
{
|
|
304
|
+
AbstractState tmpState = abstractTrace[pred];
|
|
305
|
+
if (intraCfgEdge->getCondition())
|
|
319
306
|
{
|
|
320
|
-
if (
|
|
321
|
-
|
|
322
|
-
// state has been refined in-place by isBranchFeasible
|
|
307
|
+
if (isBranchFeasible(intraCfgEdge, tmpState))
|
|
308
|
+
workList.push_back(tmpState);
|
|
323
309
|
}
|
|
324
|
-
if (hasAbstractState(dst))
|
|
325
|
-
abstractTrace[dst].joinWith(state);
|
|
326
310
|
else
|
|
327
|
-
|
|
311
|
+
{
|
|
312
|
+
workList.push_back(tmpState);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
else if (SVFUtil::isa<CallCFGEdge>(edge))
|
|
316
|
+
{
|
|
317
|
+
workList.push_back(abstractTrace[pred]);
|
|
328
318
|
}
|
|
329
|
-
else if (
|
|
319
|
+
else if (SVFUtil::isa<RetCFGEdge>(edge))
|
|
330
320
|
{
|
|
331
|
-
|
|
332
|
-
// Propagate along RetCFGEdge when both endpoints are in the cycle.
|
|
333
|
-
const ICFGNode* dst = edge->getDstNode();
|
|
334
|
-
if (withinSet->find(dst) != withinSet->end())
|
|
321
|
+
switch (Options::HandleRecur())
|
|
335
322
|
{
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
323
|
+
case TOP:
|
|
324
|
+
{
|
|
325
|
+
workList.push_back(abstractTrace[pred]);
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
case WIDEN_ONLY:
|
|
329
|
+
case WIDEN_NARROW:
|
|
330
|
+
{
|
|
331
|
+
const RetICFGNode* returnSite = SVFUtil::dyn_cast<RetICFGNode>(node);
|
|
332
|
+
const CallICFGNode* callSite = returnSite->getCallICFGNode();
|
|
333
|
+
if (hasAbstractState(callSite))
|
|
334
|
+
workList.push_back(abstractTrace[pred]);
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
340
337
|
}
|
|
341
338
|
}
|
|
342
|
-
// CallCFGEdge is handled by handleFunCall
|
|
343
339
|
}
|
|
340
|
+
|
|
341
|
+
if (workList.empty())
|
|
342
|
+
return false;
|
|
343
|
+
|
|
344
|
+
auto it = workList.begin();
|
|
345
|
+
abstractTrace[node] = *it;
|
|
346
|
+
for (++it; it != workList.end(); ++it)
|
|
347
|
+
abstractTrace[node].joinWith(*it);
|
|
348
|
+
|
|
349
|
+
return true;
|
|
344
350
|
}
|
|
345
351
|
|
|
346
352
|
|
|
@@ -642,9 +648,9 @@ bool AbstractInterpretation::isBranchFeasible(const IntraCFGEdge* intraEdge,
|
|
|
642
648
|
return true;
|
|
643
649
|
}
|
|
644
650
|
/**
|
|
645
|
-
* Handle an ICFG node: execute statements
|
|
646
|
-
* The node's pre-state must already be in abstractTrace (set by
|
|
647
|
-
*
|
|
651
|
+
* Handle an ICFG node: execute statements on the current abstract state.
|
|
652
|
+
* The node's pre-state must already be in abstractTrace (set by
|
|
653
|
+
* mergeStatesFromPredecessors, or by handleGlobalNode for the global node).
|
|
648
654
|
* Returns true if the abstract state has changed, false if fixpoint reached or unreachable.
|
|
649
655
|
*/
|
|
650
656
|
bool AbstractInterpretation::handleICFGNode(const ICFGNode* node)
|
|
@@ -722,12 +728,13 @@ void AbstractInterpretation::handleFunction(const ICFGNode* funEntry, const Call
|
|
|
722
728
|
if (const ICFGSingletonWTO* singleton = SVFUtil::dyn_cast<ICFGSingletonWTO>(comp))
|
|
723
729
|
{
|
|
724
730
|
const ICFGNode* node = singleton->getICFGNode();
|
|
725
|
-
|
|
726
|
-
|
|
731
|
+
if (mergeStatesFromPredecessors(node))
|
|
732
|
+
handleICFGNode(node);
|
|
727
733
|
}
|
|
728
734
|
else if (const ICFGCycleWTO* cycle = SVFUtil::dyn_cast<ICFGCycleWTO>(comp))
|
|
729
735
|
{
|
|
730
|
-
|
|
736
|
+
if (mergeStatesFromPredecessors(cycle->head()->getICFGNode()))
|
|
737
|
+
handleLoopOrRecursion(cycle, caller);
|
|
731
738
|
}
|
|
732
739
|
}
|
|
733
740
|
}
|
|
@@ -883,78 +890,36 @@ void AbstractInterpretation::handleFunCall(const CallICFGNode *callNode)
|
|
|
883
890
|
{
|
|
884
891
|
AbstractState& as = getAbstractState(callNode);
|
|
885
892
|
abstractTrace[callNode] = as;
|
|
886
|
-
// Skip recursive callsites (within SCC); entry calls are not skipped.
|
|
887
|
-
// For skipped recursive calls, propagate the caller's state to the callee
|
|
888
|
-
// entry as a back-edge contribution. This is needed because the IntraCFGEdge
|
|
889
|
-
// from CallNode to RetNode was removed by the ICFG builder (replaced by
|
|
890
|
-
// CallCFGEdge + RetCFGEdge), so propagateToSuccessor cannot propagate the
|
|
891
|
-
// back-edge. We manually push the CallPE parameters to the callee entry.
|
|
892
893
|
if (skipRecursiveCall(callNode))
|
|
893
|
-
{
|
|
894
|
-
const FunObjVar* callee = getCallee(callNode);
|
|
895
|
-
const ICFGNode* calleeEntry = icfg->getFunEntryICFGNode(callee);
|
|
896
|
-
// Push caller's state to callee entry (back-edge of recursive cycle)
|
|
897
|
-
if (hasAbstractState(calleeEntry))
|
|
898
|
-
abstractTrace[calleeEntry].joinWith(abstractTrace[callNode]);
|
|
899
|
-
else
|
|
900
|
-
abstractTrace[calleeEntry] = abstractTrace[callNode];
|
|
901
894
|
return;
|
|
902
|
-
}
|
|
903
895
|
|
|
904
896
|
// Direct call: callee is known
|
|
905
897
|
if (const FunObjVar* callee = callNode->getCalledFunction())
|
|
906
898
|
{
|
|
907
899
|
const ICFGNode* calleeEntry = icfg->getFunEntryICFGNode(callee);
|
|
908
|
-
const ICFGNode* calleeExit = icfg->getFunExitICFGNode(callee);
|
|
909
|
-
// Push caller's state to callee entry so CallPE can copy parameters
|
|
910
|
-
abstractTrace[calleeEntry] = abstractTrace[callNode];
|
|
911
900
|
handleFunction(calleeEntry, callNode);
|
|
912
|
-
//
|
|
901
|
+
// Resume return node from caller's state (context-insensitive).
|
|
902
|
+
// Callee's side effects are reflected through shared abstractTrace.
|
|
913
903
|
const RetICFGNode* retNode = callNode->getRetICFGNode();
|
|
914
|
-
|
|
915
|
-
abstractTrace[retNode] = abstractTrace[calleeExit];
|
|
916
|
-
else
|
|
917
|
-
abstractTrace[retNode] = abstractTrace[callNode];
|
|
904
|
+
abstractTrace[retNode] = abstractTrace[callNode];
|
|
918
905
|
return;
|
|
919
906
|
}
|
|
920
907
|
|
|
921
908
|
// Indirect call: use Andersen's call graph to get all resolved callees.
|
|
922
|
-
// The call graph was built during PreAnalysis::initWTO() by running Andersen's pointer analysis,
|
|
923
|
-
// which over-approximates the set of possible targets for each indirect callsite.
|
|
924
909
|
const RetICFGNode* retNode = callNode->getRetICFGNode();
|
|
925
910
|
if (callGraph->hasIndCSCallees(callNode))
|
|
926
911
|
{
|
|
927
912
|
const auto& callees = callGraph->getIndCSCallees(callNode);
|
|
928
|
-
bool firstCallee = true;
|
|
929
913
|
for (const FunObjVar* callee : callees)
|
|
930
914
|
{
|
|
931
915
|
if (callee->isDeclaration())
|
|
932
916
|
continue;
|
|
933
917
|
const ICFGNode* calleeEntry = icfg->getFunEntryICFGNode(callee);
|
|
934
|
-
const ICFGNode* calleeExit = icfg->getFunExitICFGNode(callee);
|
|
935
|
-
// Push caller's state to callee entry
|
|
936
|
-
abstractTrace[calleeEntry] = abstractTrace[callNode];
|
|
937
918
|
handleFunction(calleeEntry, callNode);
|
|
938
|
-
// Use callee exit state for retNode (first callee assigns, rest join)
|
|
939
|
-
if (hasAbstractState(calleeExit))
|
|
940
|
-
{
|
|
941
|
-
if (firstCallee)
|
|
942
|
-
{
|
|
943
|
-
abstractTrace[retNode] = abstractTrace[calleeExit];
|
|
944
|
-
firstCallee = false;
|
|
945
|
-
}
|
|
946
|
-
else
|
|
947
|
-
abstractTrace[retNode].joinWith(abstractTrace[calleeExit]);
|
|
948
|
-
}
|
|
949
919
|
}
|
|
950
|
-
// If no callee was processed, fall back to caller's state
|
|
951
|
-
if (firstCallee)
|
|
952
|
-
abstractTrace[retNode] = abstractTrace[callNode];
|
|
953
|
-
}
|
|
954
|
-
else
|
|
955
|
-
{
|
|
956
|
-
abstractTrace[retNode] = abstractTrace[callNode];
|
|
957
920
|
}
|
|
921
|
+
// Resume return node from caller's state (context-insensitive)
|
|
922
|
+
abstractTrace[retNode] = abstractTrace[callNode];
|
|
958
923
|
}
|
|
959
924
|
|
|
960
925
|
/// Handle WTO cycle (loop or recursive function) using widening/narrowing iteration.
|
|
@@ -1001,151 +966,71 @@ void AbstractInterpretation::handleLoopOrRecursion(const ICFGCycleWTO* cycle, co
|
|
|
1001
966
|
{
|
|
1002
967
|
const ICFGNode* cycle_head = cycle->head()->getICFGNode();
|
|
1003
968
|
|
|
1004
|
-
// TOP mode for recursive function cycles:
|
|
1005
|
-
// all stores and return value to TOP, maintaining original semantics
|
|
969
|
+
// TOP mode for recursive function cycles: set all stores and return value to TOP
|
|
1006
970
|
if (Options::HandleRecur() == TOP && isRecursiveFun(cycle_head->getFun()))
|
|
1007
971
|
{
|
|
1008
972
|
if (caller)
|
|
1009
|
-
{
|
|
1010
973
|
handleRecursiveCall(caller);
|
|
1011
|
-
}
|
|
1012
974
|
return;
|
|
1013
975
|
}
|
|
1014
976
|
|
|
1015
|
-
//
|
|
1016
|
-
// outside the cycle, already propagated before we enter the cycle).
|
|
1017
|
-
// This is fixed across all iterations; only back-edge contributions change.
|
|
1018
|
-
AbstractState externalPre;
|
|
1019
|
-
if (hasAbstractState(cycle_head))
|
|
1020
|
-
externalPre = abstractTrace[cycle_head];
|
|
1021
|
-
|
|
1022
|
-
// Collect all cycle body node pointers (excluding head) for clearing,
|
|
1023
|
-
// and build cycleNodes set (head + body) for restricting propagation.
|
|
1024
|
-
std::vector<const ICFGNode*> bodyNodes;
|
|
1025
|
-
Set<const ICFGNode*> cycleNodes;
|
|
1026
|
-
cycleNodes.insert(cycle_head);
|
|
1027
|
-
for (const ICFGWTOComp* comp : cycle->getWTOComponents())
|
|
1028
|
-
{
|
|
1029
|
-
if (const ICFGSingletonWTO* singleton = SVFUtil::dyn_cast<ICFGSingletonWTO>(comp))
|
|
1030
|
-
{
|
|
1031
|
-
bodyNodes.push_back(singleton->getICFGNode());
|
|
1032
|
-
cycleNodes.insert(singleton->getICFGNode());
|
|
1033
|
-
}
|
|
1034
|
-
// Sub-cycle heads are handled recursively; their state is managed
|
|
1035
|
-
// by their own handleLoopOrRecursion call, but we still need to
|
|
1036
|
-
// clear them to avoid stale accumulation from previous outer iterations.
|
|
1037
|
-
else if (const ICFGCycleWTO* subCycle = SVFUtil::dyn_cast<ICFGCycleWTO>(comp))
|
|
1038
|
-
{
|
|
1039
|
-
bodyNodes.push_back(subCycle->head()->getICFGNode());
|
|
1040
|
-
cycleNodes.insert(subCycle->head()->getICFGNode());
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
// WIDEN_ONLY / WIDEN_NARROW modes (and regular loops): iterate until fixpoint.
|
|
1045
|
-
// Widening/narrowing is applied to the head's PRE-state (before execution).
|
|
1046
|
-
// Each iteration: widen/narrow pre-state -> execute head -> propagate ->
|
|
1047
|
-
// execute body -> collect back-edge -> rebuild pre-state for next iteration.
|
|
977
|
+
// Iterate until fixpoint with widening/narrowing on the cycle head.
|
|
1048
978
|
bool increasing = true;
|
|
1049
979
|
u32_t widen_delay = Options::WidenDelay();
|
|
1050
|
-
AbstractState prev_head_pre;
|
|
1051
|
-
if (hasAbstractState(cycle_head))
|
|
1052
|
-
prev_head_pre = abstractTrace[cycle_head];
|
|
1053
|
-
|
|
1054
980
|
for (u32_t cur_iter = 0;; cur_iter++)
|
|
1055
981
|
{
|
|
1056
|
-
// Clear cycle body states to prevent stale accumulation from previous iteration.
|
|
1057
|
-
for (const ICFGNode* bodyNode : bodyNodes)
|
|
1058
|
-
abstractTrace.erase(bodyNode);
|
|
1059
|
-
|
|
1060
|
-
// Apply widening or narrowing to the head's pre-state.
|
|
1061
|
-
// Compare current pre-state with the previous iteration's pre-state.
|
|
1062
982
|
if (cur_iter >= widen_delay)
|
|
1063
983
|
{
|
|
1064
|
-
|
|
984
|
+
// Save state before processing head
|
|
985
|
+
AbstractState prev_head_state = abstractTrace[cycle_head];
|
|
986
|
+
|
|
987
|
+
// Process cycle head: merge from predecessors, then execute statements
|
|
988
|
+
// (uses same gated pattern as handleWTOComponent in origin/master)
|
|
989
|
+
if (mergeStatesFromPredecessors(cycle_head))
|
|
990
|
+
handleICFGNode(cycle_head);
|
|
991
|
+
AbstractState cur_head_state = abstractTrace[cycle_head];
|
|
992
|
+
|
|
1065
993
|
if (increasing)
|
|
1066
994
|
{
|
|
1067
|
-
abstractTrace[cycle_head] =
|
|
1068
|
-
if (abstractTrace[cycle_head] ==
|
|
995
|
+
abstractTrace[cycle_head] = prev_head_state.widening(cur_head_state);
|
|
996
|
+
if (abstractTrace[cycle_head] == prev_head_state)
|
|
1069
997
|
{
|
|
998
|
+
// Widening fixpoint reached; switch to narrowing phase.
|
|
1070
999
|
increasing = false;
|
|
1071
|
-
|
|
1000
|
+
continue;
|
|
1072
1001
|
}
|
|
1073
1002
|
}
|
|
1074
1003
|
else
|
|
1075
1004
|
{
|
|
1076
1005
|
if (!shouldApplyNarrowing(cycle_head->getFun()))
|
|
1077
1006
|
break;
|
|
1078
|
-
|
|
1079
|
-
abstractTrace[cycle_head]
|
|
1080
|
-
if (abstractTrace[cycle_head] == prev_head_pre)
|
|
1007
|
+
abstractTrace[cycle_head] = prev_head_state.narrowing(cur_head_state);
|
|
1008
|
+
if (abstractTrace[cycle_head] == prev_head_state)
|
|
1081
1009
|
break;
|
|
1082
1010
|
}
|
|
1083
1011
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
// Propagate head's post-state to body successor nodes within the cycle,
|
|
1091
|
-
// then erase head so the back-edge from body tail lands in a clean slot
|
|
1092
|
-
// (not mixed with head's post-state).
|
|
1093
|
-
propagateToSuccessor(cycle_head, &cycleNodes);
|
|
1094
|
-
abstractTrace.erase(cycle_head);
|
|
1012
|
+
else
|
|
1013
|
+
{
|
|
1014
|
+
// Before widen_delay: process cycle head with gated pattern
|
|
1015
|
+
if (mergeStatesFromPredecessors(cycle_head))
|
|
1016
|
+
handleICFGNode(cycle_head);
|
|
1017
|
+
}
|
|
1095
1018
|
|
|
1096
|
-
// Process cycle body components (
|
|
1019
|
+
// Process cycle body components (each with gated merge+handle)
|
|
1097
1020
|
for (const ICFGWTOComp* comp : cycle->getWTOComponents())
|
|
1098
1021
|
{
|
|
1099
1022
|
if (const ICFGSingletonWTO* singleton = SVFUtil::dyn_cast<ICFGSingletonWTO>(comp))
|
|
1100
1023
|
{
|
|
1101
|
-
const ICFGNode*
|
|
1102
|
-
|
|
1103
|
-
|
|
1024
|
+
const ICFGNode* node = singleton->getICFGNode();
|
|
1025
|
+
if (mergeStatesFromPredecessors(node))
|
|
1026
|
+
handleICFGNode(node);
|
|
1104
1027
|
}
|
|
1105
1028
|
else if (const ICFGCycleWTO* subCycle = SVFUtil::dyn_cast<ICFGCycleWTO>(comp))
|
|
1106
1029
|
{
|
|
1107
|
-
|
|
1030
|
+
if (mergeStatesFromPredecessors(subCycle->head()->getICFGNode()))
|
|
1031
|
+
handleLoopOrRecursion(subCycle, caller);
|
|
1108
1032
|
}
|
|
1109
1033
|
}
|
|
1110
|
-
|
|
1111
|
-
// After body processing, abstractTrace[cycle_head] holds only the
|
|
1112
|
-
// back-edge contribution (if any). Rebuild head's pre-state for the
|
|
1113
|
-
// next iteration: externalPre joined with back-edge.
|
|
1114
|
-
if (hasAbstractState(cycle_head))
|
|
1115
|
-
{
|
|
1116
|
-
AbstractState backEdge = abstractTrace[cycle_head];
|
|
1117
|
-
abstractTrace[cycle_head] = externalPre;
|
|
1118
|
-
abstractTrace[cycle_head].joinWith(backEdge);
|
|
1119
|
-
}
|
|
1120
|
-
else
|
|
1121
|
-
{
|
|
1122
|
-
abstractTrace[cycle_head] = externalPre;
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
// Final pass: re-execute all cycle nodes and propagate without restriction.
|
|
1127
|
-
// During iterations, propagation was restricted to cycle-internal nodes.
|
|
1128
|
-
// Now re-execute and propagate from all cycle nodes without restriction,
|
|
1129
|
-
// so that exit edges (outside the cycle) receive the converged states.
|
|
1130
|
-
// We must clear body nodes first and re-process them from scratch using
|
|
1131
|
-
// the converged head pre-state, since body nodes may contain stale states
|
|
1132
|
-
// from the last iteration that predate the final head re-execution.
|
|
1133
|
-
for (const ICFGNode* bodyNode : bodyNodes)
|
|
1134
|
-
abstractTrace.erase(bodyNode);
|
|
1135
|
-
handleICFGNode(cycle_head);
|
|
1136
|
-
propagateToSuccessor(cycle_head);
|
|
1137
|
-
for (const ICFGWTOComp* comp : cycle->getWTOComponents())
|
|
1138
|
-
{
|
|
1139
|
-
if (const ICFGSingletonWTO* singleton = SVFUtil::dyn_cast<ICFGSingletonWTO>(comp))
|
|
1140
|
-
{
|
|
1141
|
-
const ICFGNode* bodyNode = singleton->getICFGNode();
|
|
1142
|
-
handleICFGNode(bodyNode);
|
|
1143
|
-
propagateToSuccessor(bodyNode);
|
|
1144
|
-
}
|
|
1145
|
-
else if (const ICFGCycleWTO* subCycle = SVFUtil::dyn_cast<ICFGCycleWTO>(comp))
|
|
1146
|
-
{
|
|
1147
|
-
handleLoopOrRecursion(subCycle, caller);
|
|
1148
|
-
}
|
|
1149
1034
|
}
|
|
1150
1035
|
}
|
|
1151
1036
|
|