RFR: 8255452: Doing GC during JVMTI MethodExit event posting breaks return oop

Erik Österlund eosterlund at openjdk.java.net
Fri Oct 30 16:05:55 UTC 2020


On Fri, 30 Oct 2020 14:20:42 GMT, Erik Österlund <eosterlund at openjdk.org> wrote:

>> Marked as reviewed by dlong (Reviewer).
>
>> I think you've discovered JDK-6449023. And you fix looks like the workaround I tried:
>> https://bugs.openjdk.java.net/browse/JDK-6449023?focusedCommentId=14206078&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-14206078
> 
> Oh wow. I had no idea people have been having issues with this since 2009! Thanks for the pointer. Well, let's hope we can finally close it now after marinating the bug for 11 years.

> Hi Erik,
> 
> is it possible for GC to mistake a primitive value for a reference when posting the exit event?
> 
> My understanding is: we are at a random bci of a method that is forced to return early. The expression stack is emptied and the return value is pushed on the expression stack then we call into the interpreter runtime to post the JVMTI method exit event during which we come to a safepoint for GC. The oop map for the bci does not cover this forced early return and if the return value is an object then the reference pushed on the expression stack before is not updated by GC. With your fix the value is updated if it is a reference.
> 
> If this is correct then to me it appears as if GC can also crash because the oop map for the random bci tells there has to be a reference at the stack position of the return value if it actually is a primitive value.

I think what you are saying is true. Note though that the return value of ForceEarlyReturn is installed with a handshake. The handshake polls of the interpreter are emitted in loop backedges and returns. At loop backedges, the expression stack is empty (required by OSR), and at returns the types match correctly. However, if an arbitrary bytecode performs a runtime call with call_VM() while the bottom of the expression stack is an oop, then I think there is an issue. At that call_VM, the early return value could get installed, and when the C++ function returns, we check for early returns, further dispatching to an unwind routine that posts the MethodExit notification. If we GC during this MethodExit notification, then I think you can crash the GC. The GC code generates an oop map for the frame, checking what the types in the expression stack should be. The early return int is pushed on the slot intersecting with the bottom entry in the expression stack. That bottom entry could be an o
 op, and the early return value could be an int. Then the early return int will be passed to the oop closure, which should result in a crash.

So I suspect that almost always, the handshake installing the ForceEarlyReturn value is installed with a handshake in a bytecode backedge or at a return, where the interpreter safepoint polls for the fast path code. Then you won't notice the issue. But in the rare scenario that the ForceEarlyReturn value is installed in a slow path call from a random bytecode... I can't see how that would work correctly.

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

PR: https://git.openjdk.java.net/jdk/pull/930


More information about the hotspot-dev mailing list