On Tue, 11 Jul 2023 15:47:35 GMT, Volker Simonis <simo...@openjdk.org> wrote:

>> As the included jtreg test demonstrates, `StackWalker.getCallerClass()` can 
>> throw an `UnsupportedOperationException` if called reflectively. Currently 
>> this only happens if we invoke `StackWalker.getCallerClass()` recursively 
>> reflectively, but this issue will become more prominent once we fix 
>> [JDK-8285447](https://bugs.openjdk.org/browse/JDK-8285447). The gory details 
>> follow below:
>> 
>> The protocol between the Java API and the JVM for 
>> `StackWalker.getCallerClass()/walk()` is as follows:
>> - On the Java side, `StackWalker` calls into `StackStreamFactory` for the 
>> real work.
>> - For `StackWalker.getCallerClass()` `StackStreamFactory` basically creates 
>> a `Class[]` which will be passed down and filled in the JVM. For 
>> `StackWalker.walk()` it will normally be a `StackFrameInfo[]` (or a 
>> `LiveStackFrameInfo[]` if the internal `ExtendedOption.LOCALS_AND_OPERANDS` 
>> option was used).
>> - The default size of this arrays is currently 
>> `StackStreamFactory.SMALL_BATCH` which is 8 (but see 
>> [JDK-8285447](https://bugs.openjdk.org/browse/JDK-8285447)).
>> - `StackStreamFactory` than calls `AbstractStackWalker.callStackWalk()` 
>> which is a natively implemented in the VM by `JVM_CallStackWalk()`.
>> -  `JVM_CallStackWalk()` calls `StackWalk::walk()` which calls 
>> `StackWalk::fetchFirstBatch()` which calls `StackWalk::fill_in_frames()` 
>> which walks the stack and fills in the available class/stackframe slots in 
>> the passed in array until the array is full or there are no more stack 
>> frames,
>> - Once  `StackWalk::fill_in_frames()` returns, 
>> `StackWalk::fetchFirstBatch()` calls back to Java by invoking 
>> `AbstractStackWalker::doStackWalk()` to consume the result.
>> - `AbstractStackWalker::doStackWalk()` calls `consumeFrames()` (which is 
>> overridden depending on whether we initially called `getCallerClass()` or 
>> `walk()`) which consumes the frames until it either finishes (e.g. finds the 
>> caller class) or until there are no more frames.
>> - In the latter case `consumeFrames()` will call into the the VM again by 
>> calling `AbstractStackWalker.fetchStackFrames()` to fetch additional frames 
>> from the stack.
>> - `AbstractStackWalker.fetchStackFrames()` is implemented by 
>> `JVM_MoreStackWalk()` which calls `StackWalk::fetchNextBatch()` which calls 
>> `StackWalk::fill_in_frames()` (the same method that already fetched the 
>> initial batch of frames).
>> 
>> Following is a stacktrace of what I've explained so far:
>> 
>> Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native 
>> code)
>> V  [libjvm.so+0x1...
>
> Volker Simonis has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Fixed case when calling getCallerClass() from a @CallerSensitive method 
> reflectively

src/hotspot/share/prims/stackwalk.cpp line 164:

> 162:     method->method_holder()->is_subtype_of(constructor_accessor) ||
> 163:     // MethodHandle frames are not hidden and 
> StackWalker::getCallerClass has to filter them out
> 164:     method->method_holder()->name()->starts_with("java/lang/invoke"));

Shouldn’t this be:
Suggestion:

    method->method_holder()->name()->starts_with("java/lang/invoke/"));

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/14773#discussion_r1263467101

Reply via email to