StackWalker::getCallerClass throws UnsupportedOperationException
Hi StackWalker::getCallerClass can throw "UnsupportedOperationException: StackWalker::getCallerClass called from @CallerSensitive", depending on how the underlying fetchNextBatch/fill_in_frames splits the stacktrace. This seems to be a result of what was introduced in JDK-8157464. The following code example produces the exception (Tested on the jdk.java.net releases of OpenJDK 10 and 11-ea build 28): // ----- snip ---- package com.test; import java.lang.reflect.Method; public class Main { public static void main(String[] args) throws Exception { Method method = Main.class.getDeclaredMethod("bar"); Method m = Method.class.getMethod("invoke", Object.class, Object[].class); // get 'm' past compilation threshold for (int i = 0; i < 15; i++) { m.invoke(Main.class.getDeclaredMethod("dummy"), null, null); } m.invoke(m, m, new Object[] {method, new Object[] {null, null}}); } static void dummy() { } static void bar() { System.out.println(StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass()); } } // ----- snip ---- The above code is constructed so Method::invoke ends up as the frame for which index==start_index in fill_in_frames, thus causing the exception. For example output, including stackwalk debug output, see below. // ----- snip ---- $ java -Xlog:stackwalk=debug com.test.Main [0.154s][debug][stackwalk] Start walking: mode 6 skip 0 frames batch size 6 [0.155s][debug][stackwalk] skip java.lang.StackStreamFactory$AbstractStackWalker::callStackWalk [0.156s][debug][stackwalk] skip java.lang.StackStreamFactory$AbstractStackWalker::beginStackWalk [0.157s][debug][stackwalk] skip java.lang.StackStreamFactory$AbstractStackWalker::walk [0.158s][debug][stackwalk] skip java.lang.StackStreamFactory$CallerClassFinder::findCaller [0.159s][debug][stackwalk] skip java.lang.StackWalker::getCallerClass [0.160s][debug][stackwalk] fill_in_frames limit=6 start=2 frames length=8 [0.161s][debug][stackwalk] 2: frame method: com.test.Main::bar bci=9 [0.162s][debug][stackwalk] 3: frame method: jdk.internal.reflect.NativeMethodAccessorImpl::invoke0 bci=0 [0.162s][debug][stackwalk] 4: frame method: jdk.internal.reflect.NativeMethodAccessorImpl::invoke bci=100 [0.163s][debug][stackwalk] 5: frame method: jdk.internal.reflect.DelegatingMethodAccessorImpl::invoke bci=6 [0.163s][debug][stackwalk] 6: frame method: java.lang.reflect.Method::invoke bci=59 [0.168s][debug][stackwalk] 7: frame method: jdk.internal.reflect.GeneratedMethodAccessor1::invoke bci=48 [0.169s][debug][stackwalk] StackWalk::fetchNextBatch frame_count 8 existing_stream 0x000000a5b8ffb5f0 start 2 frames 10 [0.170s][debug][stackwalk] fill_in_frames limit=8 start=2 frames length=10 [0.171s][debug][stackwalk] 2: frame method: jdk.internal.reflect.DelegatingMethodAccessorImpl::invoke bci=6 [0.171s][debug][stackwalk] 3: frame method: java.lang.reflect.Method::invoke bci=59 [0.172s][debug][stackwalk] 4: frame method: jdk.internal.reflect.GeneratedMethodAccessor1::invoke bci=48 [0.173s][debug][stackwalk] 5: frame method: jdk.internal.reflect.DelegatingMethodAccessorImpl::invoke bci=6 [0.174s][debug][stackwalk] 6: frame method: java.lang.reflect.Method::invoke bci=59 [0.175s][debug][stackwalk] 7: frame method: jdk.internal.reflect.NativeMethodAccessorImpl::invoke0 bci=0 [0.175s][debug][stackwalk] 8: frame method: jdk.internal.reflect.NativeMethodAccessorImpl::invoke bci=100 [0.179s][debug][stackwalk] 9: frame method: jdk.internal.reflect.DelegatingMethodAccessorImpl::invoke bci=6 [0.180s][debug][stackwalk] StackWalk::fetchNextBatch frame_count 8 existing_stream 0x000000a5b8ffb5f0 start 2 frames 10 [0.181s][debug][stackwalk] fill_in_frames limit=8 start=2 frames length=10 [0.181s][debug][stackwalk] 2: frame method: java.lang.reflect.Method::invoke bci=59 Exception in thread "main" java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at com.test.Main.main(Main.java:15) Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) ... 5 more Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) ... 8 more Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) ... 11 more Caused by: java.lang.UnsupportedOperationException: StackWalker::getCallerClass called from @CallerSensitive java.lang.reflect.Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; method at java.base/java.lang.StackStreamFactory$AbstractStackWalker.fetchStackFrames(Native Method) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.fetchStackFrames(StackStreamFactory.java:386) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.getNextBatch(StackStreamFactory.java:322) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.peekFrame(StackStreamFactory.java:263) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.hasNext(StackStreamFactory.java:351) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.nextFrame(StackStreamFactory.java:336) at java.base/java.lang.StackStreamFactory$CallerClassFinder.consumeFrames(StackStreamFactory.java:683) at java.base/java.lang.StackStreamFactory$CallerClassFinder.consumeFrames(StackStreamFactory.java:612) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.doStackWalk(StackStreamFactory.java:306) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.callStackWalk(Native Method) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.beginStackWalk(StackStreamFactory.java:370) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.walk(StackStreamFactory.java:243) at java.base/java.lang.StackStreamFactory$CallerClassFinder.findCaller(StackStreamFactory.java:670) at java.base/java.lang.StackWalker.getCallerClass(StackWalker.java:600) at com.test.Main.bar(Main.java:21) ... 15 more // ----- snip ---- Kind regards /Michael
Thanks for reporting this. I have created: https://bugs.openjdk.java.net/browse/JDK-8210375 and will look into it. Mandy On 9/4/18 4:26 AM, Michael Rasmussen wrote:
Hi
StackWalker::getCallerClass can throw "UnsupportedOperationException: StackWalker::getCallerClass called from @CallerSensitive", depending on how the underlying fetchNextBatch/fill_in_frames splits the stacktrace.
This seems to be a result of what was introduced in JDK-8157464.
The following code example produces the exception (Tested on the jdk.java.net releases of OpenJDK 10 and 11-ea build 28):
// ----- snip ---- package com.test;
import java.lang.reflect.Method;
public class Main { public static void main(String[] args) throws Exception { Method method = Main.class.getDeclaredMethod("bar"); Method m = Method.class.getMethod("invoke", Object.class, Object[].class);
// get 'm' past compilation threshold for (int i = 0; i < 15; i++) { m.invoke(Main.class.getDeclaredMethod("dummy"), null, null); }
m.invoke(m, m, new Object[] {method, new Object[] {null, null}}); }
static void dummy() { }
static void bar() { System.out.println(StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE).getCallerClass()); } } // ----- snip ----
The above code is constructed so Method::invoke ends up as the frame for which index==start_index in fill_in_frames, thus causing the exception.
For example output, including stackwalk debug output, see below.
// ----- snip ---- $ java -Xlog:stackwalk=debug com.test.Main [0.154s][debug][stackwalk] Start walking: mode 6 skip 0 frames batch size 6 [0.155s][debug][stackwalk] skip java.lang.StackStreamFactory$AbstractStackWalker::callStackWalk [0.156s][debug][stackwalk] skip java.lang.StackStreamFactory$AbstractStackWalker::beginStackWalk [0.157s][debug][stackwalk] skip java.lang.StackStreamFactory$AbstractStackWalker::walk [0.158s][debug][stackwalk] skip java.lang.StackStreamFactory$CallerClassFinder::findCaller [0.159s][debug][stackwalk] skip java.lang.StackWalker::getCallerClass [0.160s][debug][stackwalk] fill_in_frames limit=6 start=2 frames length=8 [0.161s][debug][stackwalk] 2: frame method: com.test.Main::bar bci=9 [0.162s][debug][stackwalk] 3: frame method: jdk.internal.reflect.NativeMethodAccessorImpl::invoke0 bci=0 [0.162s][debug][stackwalk] 4: frame method: jdk.internal.reflect.NativeMethodAccessorImpl::invoke bci=100 [0.163s][debug][stackwalk] 5: frame method: jdk.internal.reflect.DelegatingMethodAccessorImpl::invoke bci=6 [0.163s][debug][stackwalk] 6: frame method: java.lang.reflect.Method::invoke bci=59 [0.168s][debug][stackwalk] 7: frame method: jdk.internal.reflect.GeneratedMethodAccessor1::invoke bci=48 [0.169s][debug][stackwalk] StackWalk::fetchNextBatch frame_count 8 existing_stream 0x000000a5b8ffb5f0 start 2 frames 10 [0.170s][debug][stackwalk] fill_in_frames limit=8 start=2 frames length=10 [0.171s][debug][stackwalk] 2: frame method: jdk.internal.reflect.DelegatingMethodAccessorImpl::invoke bci=6 [0.171s][debug][stackwalk] 3: frame method: java.lang.reflect.Method::invoke bci=59 [0.172s][debug][stackwalk] 4: frame method: jdk.internal.reflect.GeneratedMethodAccessor1::invoke bci=48 [0.173s][debug][stackwalk] 5: frame method: jdk.internal.reflect.DelegatingMethodAccessorImpl::invoke bci=6 [0.174s][debug][stackwalk] 6: frame method: java.lang.reflect.Method::invoke bci=59 [0.175s][debug][stackwalk] 7: frame method: jdk.internal.reflect.NativeMethodAccessorImpl::invoke0 bci=0 [0.175s][debug][stackwalk] 8: frame method: jdk.internal.reflect.NativeMethodAccessorImpl::invoke bci=100 [0.179s][debug][stackwalk] 9: frame method: jdk.internal.reflect.DelegatingMethodAccessorImpl::invoke bci=6 [0.180s][debug][stackwalk] StackWalk::fetchNextBatch frame_count 8 existing_stream 0x000000a5b8ffb5f0 start 2 frames 10 [0.181s][debug][stackwalk] fill_in_frames limit=8 start=2 frames length=10 [0.181s][debug][stackwalk] 2: frame method: java.lang.reflect.Method::invoke bci=59 Exception in thread "main" java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at com.test.Main.main(Main.java:15) Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) ... 5 more Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) ... 8 more Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) ... 11 more Caused by: java.lang.UnsupportedOperationException: StackWalker::getCallerClass called from @CallerSensitive java.lang.reflect.Method.invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; method at java.base/java.lang.StackStreamFactory$AbstractStackWalker.fetchStackFrames(Native Method) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.fetchStackFrames(StackStreamFactory.java:386) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.getNextBatch(StackStreamFactory.java:322) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.peekFrame(StackStreamFactory.java:263) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.hasNext(StackStreamFactory.java:351) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.nextFrame(StackStreamFactory.java:336) at java.base/java.lang.StackStreamFactory$CallerClassFinder.consumeFrames(StackStreamFactory.java:683) at java.base/java.lang.StackStreamFactory$CallerClassFinder.consumeFrames(StackStreamFactory.java:612) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.doStackWalk(StackStreamFactory.java:306) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.callStackWalk(Native Method) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.beginStackWalk(StackStreamFactory.java:370) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.walk(StackStreamFactory.java:243) at java.base/java.lang.StackStreamFactory$CallerClassFinder.findCaller(StackStreamFactory.java:670) at java.base/java.lang.StackWalker.getCallerClass(StackWalker.java:600) at com.test.Main.bar(Main.java:21) ... 15 more // ----- snip ----
Kind regards /Michael
participants (2)
-
mandy chung
-
Michael Rasmussen