Here is a simple Java application:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main {
interface MyInterface {
void myMethod();
}
public static void main(String[] args) {
MyInterface myInterface = (MyInterface) Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[] {MyInterface.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(proxy, args);
}
});
myInterface.myMethod();
}
}
I would expect to get a simple StackOverflowError
here, because I am recursively calling the same method on the proxy instance.
However, the stack trace produced by the exception contains millions of lines and hundreds of MBs in size.
The first part of the stack trace starts like this:
java.lang.reflect.UndeclaredThrowableException
at $Proxy0.myMethod(Unknown Source)
at Main.main(Main.java:22)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at Main$1.invoke(Main.java:18)
... 2 more
Caused by: java.lang.reflect.UndeclaredThrowableException
at $Proxy0.myMethod(Unknown Source)
... 7 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at Main$1.invoke(Main.java:18)
... 8 more
and extends to:
Caused by: java.lang.reflect.UndeclaredThrowableException
at $Proxy0.myMethod(Unknown Source)
... 1022 more
Then follow millions of lines like:
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at Main$1.invoke(Main.java:18)
at $Proxy0.myMethod(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at Main$1.invoke(Main.java:18)
.......
and:
Caused by: java.lang.reflect.UndeclaredThrowableException
at $Proxy0.myMethod(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at Main$1.invoke(Main.java:18)
at $Proxy0.myMethod(Unknown Source)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at Main$1.invoke(Main.java:18)
.......
The last printed line is (after the repeating sequence above):
Exception: java.lang.StackOverflowError thrown from the UncaughtExceptionHandler in thread "main"
I suspected that stack trace generation mechanism was calling some methods on the proxy instance (maybe toString
to print it, or something else), thus repeating the recursion over and over again (because each method call on the proxy leads to infinite recursion), but the total count of proxy method executions is 1919 (measured by incrementing a counter in the InvocationHandler.invoke
method).
In my real use case I fixed the infinite recursion issue of course; I am just curious if anyone knows if this is some bug or there is a reasonable explanation?
Java version:
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)
Aucun commentaire:
Enregistrer un commentaire