RFR: 8359366: RunThese30M.java EXCEPTION_ACCESS_VIOLATION in JvmtiBreakpoints::clearall_in_class_at_safepoint

Leonid Mesnik lmesnik at openjdk.org
Mon Jun 30 06:05:39 UTC 2025


On Mon, 30 Jun 2025 04:42:59 GMT, David Holmes <dholmes at openjdk.org> wrote:

>> The segv/eav happens in the case if JvmtiBreakpoint::_method's class redefined old between getting the Method* from jmethodid in the 
>> JvmtiEnv::SetBreakpoint(Method* method, jlocation location) {..} and 
>> and actual setting breakpoint in the VM operation VM_ChangeBreakpoints.
>> 
>> Here are details:
>> The breakpoint is set in 2 steps.
>> 1) method jvmti_SetBreakpoint(jvmtiEnv* env, jmethodID method,  jlocation location)  convert jmethodID to Method* and call 
>>  JvmtiEnv::SetBreakpoint(Method* method, jlocation location)
>> where 
>>   JvmtiBreakpoint bp(method, location);
>> is created with this Method* 
>> Note: it is done while thread is in VM state, so Method can't become is_old while this is done.
>>  
>> 2) The VMOp is used to add breakpoint into the list 
>>  VM_ChangeBreakpoints set_breakpoint(VM_ChangeBreakpoints::SET_BREAKPOINT, &bp);
>>   VMThread::execute(&set_breakpoint);
>> to call  JvmtiBreakpoints::set_at_safepoint()
>> that can modify JvmtiBreakpoints list and set breakpoint in safepoint without synchronization.
>> 
>> So it might be possible that class redefinition  VM_RedefineClasses  operation that redefine the class with this breakpoint happens between steps 1) and 2)
>> VM_RedefineClasses::redefine_single_class()
>> clear all class-related breakpoints in the JvmtiBreakpoints, however the "problematic" breakpoint is in VMThread  queue and thus we are still continue to do this operation.
>> So in the step 2) the the JvmtiBreakpoint with 'is_old' method is added to the JvmtiBreakpoints and breakpoint is set.
>> 
>> Then old method mights be purged any time once  they are not on the stack and any access to this breakpoint could lead to usage of Metthod* _method pointing to deallocated metaspace.
>> 
>> The VM_RedefineClasses clear all breakpoints so it is correct just to don't proceed with current breakpoint also.
>> 
>> Looks, like very unlikely but reproducing with stress test after some time.
>> Verified that the crash is not reproduced anymore with corresponding test after the fix.
>> 
>> Many thanks to Coleen for detailed explanation of class redefinition.
>
> src/hotspot/share/prims/jvmtiImpl.cpp line 191:
> 
>> 189:    // the jmethod_id's method was updated if class redefintion happened for this class
>> 190:    // after JvmtBreakpoint was created but before JVM_ChangeBreakpoints started
>> 191:    // all class breakpoints are cleared during redefinition so don't set/clear this breakpoint
> 
> So basically one thread is trying to change this particular BP and it races with another thread that performs redefinition. If the redefinition thread wins then we are turning this current change into a no-op on the basis that the redefinition cleared all BPs anyway so we should not now set this one (if that was requested).
> 
> It is very unclear to me how the thread that requested the current change might respond to that request being ignored.
> 
> Please add some punctuation to the comment block as it is very hard to read at present. Thanks

Thanks for feedback.

> It is very unclear to me how the thread that requested the current change might respond to that request being ignored.
> 
The SetBreakpoint returns 'JVMTI_ERROR_NONE' just like method set breakpoint and the breakpoint was removed later by class redfinition.

BTW The alternative would be to replace  _method with new version and set breakpoint like we first redefine classes and then set breakpoint. The both approaches looks valid for specification, I think.

> Please add some punctuation to the comment block as it is very hard to read at present. Thanks
will do this a little bit later.

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

PR Review Comment: https://git.openjdk.org/jdk/pull/26031#discussion_r2174287943


More information about the hotspot-dev mailing list