Note: This is the artifact of a research project designed to help static analysis developers reason about and localize the unsoundness issues of their tool.
Description
Summary
SPARK does not correctly model dynamic proxies created through java.lang.reflect.Proxy.newProxyInstance(). Although Soot includes a virtual edge summary intended to model this API, the summary is registered as an instance invocation even though Proxy.newProxyInstance() is a static method. Consequently, the summary is never applied during call graph construction, and the proxy dispatch chain is omitted from the generated call graph.
As a result, calls made through dynamically generated proxy objects do not resolve to the corresponding InvocationHandler or generated proxy methods.
Minimal Reproduction
I have attached a Maven-based minimal project that creates a JDK dynamic proxy using Proxy.newProxyInstance(...) and immediately invokes a method through the returned proxy.
How to reproduce
Run SPARK call graph construction on the attached project using the provided Maven setup.
soot version: 4.4.1
java version: 8
The script to run the tool using JCG interface.
attachment.zip
python analysis_interface.py --framework SOOT --algorithm SPARK --project reproducing --type static --reproducing_test_case_path [path to test case directory with jcg.conf] --boundary_id 1
Observed Behavior
-
SPARK encounters the static call to Proxy.newProxyInstance(...)
-
No virtual edge summary is applied to the call site
-
The returned proxy object is therefore not connected to its generated proxy class or InvocationHandler
-
Subsequent interface dispatch through the proxy cannot be resolved
-
Consequently, the call graph contains no edge to:
com.sun.proxy.$Proxy0.bar(Object)
Expected Behavior
For programs using JDK dynamic proxies:
-
The analysis should recognize calls to Proxy.newProxyInstance(...)
-
The proxy creation should be connected to the generated proxy class and its associated InvocationHandler
-
Subsequent interface dispatch through the proxy should resolve correctly
-
A call graph edge should exist, for example:
{
"caller": "com.example.App.main(String[])",
"callee": "com.sun.proxy.$Proxy0.bar(Ljava/lang/Object;)Ljava/lang/Object;"
}
Notes on Implementation (inspected behavior)
From code inspection:
-
Soot contains a virtual edge summary for Proxy.newProxyInstance(...) in virtualedges.xml
-
However, the summary is registered with:
-
Proxy.newProxyInstance(...) is a static method
-
During call graph construction:
- static call sites query
staticinvokeEdges via getVirtualEdgesMatchingFunction(...)
- instance call sites query
instanceinvokeEdges via getVirtualEdgesMatchingSubSig(...)
-
Because the proxy summary is stored as an instance edge, the lookup for the static call returns null
-
As a result, no proxy-related virtual edges are generated, and the proxy dispatch chain is omitted from the call graph
Relevant locations:
virtualedges.xml
OnFlyCallGraphBuilder.java
VirtualEdgesSummaries.java
Impact
If the omission is unintended, it may affect analyses that rely on accurate modeling of Java's dynamic proxy mechanism. Dynamic proxies are widely used in Java frameworks such as Spring, RMI, JDK proxy-based AOP, and numerous dependency injection libraries. Missing proxy dispatch edges can lead to incomplete call graphs and reduce the effectiveness of downstream analyses such as vulnerability detection, dependency analysis, and framework behavior modeling.
Note: This is the artifact of a research project designed to help static analysis developers reason about and localize the unsoundness issues of their tool.
Description
Summary
SPARK does not correctly model dynamic proxies created through
java.lang.reflect.Proxy.newProxyInstance(). Although Soot includes a virtual edge summary intended to model this API, the summary is registered as an instance invocation even thoughProxy.newProxyInstance()is a static method. Consequently, the summary is never applied during call graph construction, and the proxy dispatch chain is omitted from the generated call graph.As a result, calls made through dynamically generated proxy objects do not resolve to the corresponding
InvocationHandleror generated proxy methods.Minimal Reproduction
I have attached a Maven-based minimal project that creates a JDK dynamic proxy using
Proxy.newProxyInstance(...)and immediately invokes a method through the returned proxy.How to reproduce
Run SPARK call graph construction on the attached project using the provided Maven setup.
soot version: 4.4.1
java version: 8
The script to run the tool using JCG interface.
attachment.zip
Observed Behavior
SPARK encounters the static call to
Proxy.newProxyInstance(...)No virtual edge summary is applied to the call site
The returned proxy object is therefore not connected to its generated proxy class or
InvocationHandlerSubsequent interface dispatch through the proxy cannot be resolved
Consequently, the call graph contains no edge to:
Expected Behavior
For programs using JDK dynamic proxies:
The analysis should recognize calls to
Proxy.newProxyInstance(...)The proxy creation should be connected to the generated proxy class and its associated
InvocationHandlerSubsequent interface dispatch through the proxy should resolve correctly
A call graph edge should exist, for example:
{ "caller": "com.example.App.main(String[])", "callee": "com.sun.proxy.$Proxy0.bar(Ljava/lang/Object;)Ljava/lang/Object;" }Notes on Implementation (inspected behavior)
From code inspection:
Soot contains a virtual edge summary for
Proxy.newProxyInstance(...)invirtualedges.xmlHowever, the summary is registered with:
invoketype="instance"Proxy.newProxyInstance(...)is a static methodDuring call graph construction:
staticinvokeEdgesviagetVirtualEdgesMatchingFunction(...)instanceinvokeEdgesviagetVirtualEdgesMatchingSubSig(...)Because the proxy summary is stored as an instance edge, the lookup for the static call returns
nullAs a result, no proxy-related virtual edges are generated, and the proxy dispatch chain is omitted from the call graph
Relevant locations:
virtualedges.xmlOnFlyCallGraphBuilder.javaVirtualEdgesSummaries.javaImpact
If the omission is unintended, it may affect analyses that rely on accurate modeling of Java's dynamic proxy mechanism. Dynamic proxies are widely used in Java frameworks such as Spring, RMI, JDK proxy-based AOP, and numerous dependency injection libraries. Missing proxy dispatch edges can lead to incomplete call graphs and reduce the effectiveness of downstream analyses such as vulnerability detection, dependency analysis, and framework behavior modeling.