JDK-8147451 : Crash in Method::checked_resolve_jmethod_id(_jmethodID*)
  • Type: Bug
  • Component: hotspot
  • Sub-Component: jvmti
  • Affected Version: 8u40
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2016-01-15
  • Updated: 2017-07-26
  • Resolved: 2016-06-11
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
8u112 b01Fixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
VisualVM's memory profiling with allocation stacktraces crashes JVM in  Method::checked_resolve_jmethod_id(). Original VisualVM bug report is here: https://java.net/jira/browse/VISUALVM-611

Example of hs_err is here:
Java crash can be observed in JDK 1.8.0_112b02 on Ubuntu x64. So fix failed. See the newly created issue for information - JDK-8161144.

Even after the suggested change I am getting crash in same location #0 Method::checked_resolve_jmethod_id (mid=0x7fff9c0ba318) at /home/shafi/Java/jdk8/jdk8u-dev/hotspot/src/share/vm/oops/method.cpp:1937 1937 if (o == NULL || o == JNIMethodBlock::_free_method || !((Metadata*)o)->is_method()) { (gdb) p o $488 = (Method *) 0x7fffddbeac50 (gdb) l 1932 } 1933 1934 Method* Method::checked_resolve_jmethod_id(jmethodID mid) { 1935 if (mid == NULL) return NULL; 1936 Method* o = resolve_jmethod_id(mid); 1937 if (o == NULL || o == JNIMethodBlock::_free_method || !((Metadata*)o)->is_method()) { 1938 return NULL; 1939 } 1940 return o; 1941 }; Seems Method object o is not valid as v-table pointer is not pointing to valid memory address " _vptr.Metadata = 0xc" (gdb) p *o $489 = { <Metadata> = { <MetaspaceObj> = {<No data fields>}, members of Metadata: _vptr.Metadata = 0xc, _valid = -574708816 }, members of Method: _constMethod = 0x7fffddbea030, _method_data = 0x7fffadd28438, _method_counters = 0x0, _access_flags = { _flags = 0 }, _vtable_index = 0, _method_size = 0, _intrinsic_id = 0 '\000', _jfr_towrite = 0 '\000', _caller_sensitive = 0 '\000', _force_inline = 0 '\000', _hidden = 0 '\000', _dont_inline = 0 '\000', _has_injected_profile = 0 '\000', _compiled_invocation_count = 0, _i2i_entry = 0x0, _adapter = 0x0, _from_compiled_entry = 0x0, _code = 0x0, _from_interpreted_entry = 0x0, static extra_stack_entries_for_jsr292 = 1 }

Able to reproduce with the latest code base in jdk8. (gdb) bt #0 0x00007ffff782c267 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:55 #1 0x00007ffff782deca in __GI_abort () at abort.c:89 #2 0x00007ffff6ccaab9 in os::abort(bool) () from /home/shafi/Java/jdk8/jdk8u-dev/build/linux-x86_64-normal-server-release/jdk/lib/amd64/server/libjvm.so #3 0x00007ffff6e87a74 in VMError::report_and_die() () from /home/shafi/Java/jdk8/jdk8u-dev/build/linux-x86_64-normal-server-release/jdk/lib/amd64/server/libjvm.so #4 0x00007ffff6cd3b77 in JVM_handle_linux_signal () from /home/shafi/Java/jdk8/jdk8u-dev/build/linux-x86_64-normal-server-release/jdk/lib/amd64/server/libjvm.so #5 0x00007ffff6cc7e88 in signalHandler(int, siginfo_t*, void*) () from /home/shafi/Java/jdk8/jdk8u-dev/build/linux-x86_64-normal-server-release/jdk/lib/amd64/server/libjvm.so #6 <signal handler called> #7 0x00007ffff6c5bac6 in Method::checked_resolve_jmethod_id(_jmethodID*) () from /home/shafi/Java/jdk8/jdk8u-dev/build/linux-x86_64-normal-server-release/jdk/lib/amd64/server/libjvm.so #8 0x00007ffff6ac9ff2 in jvmti_GetMethodDeclaringClass () from /home/shafi/Java/jdk8/jdk8u-dev/build/linux-x86_64-normal-server-release/jdk/lib/amd64/server/libjvm.so #9 0x00007fffdc6adfd3 in Java_org_netbeans_lib_profiler_server_system_Stacks_getMethodNamesForJMethodIds () from /usr/lib/jvm/java-8-oracle/lib/visualvm/profiler/lib/deployed/jdk16/linux-amd64/libprofilerinterface.so

Changed the 'Fix version" to 8 as the issue was not reproduced on 9 yet.

I was not able to reproduce it on JDK 9 yet.

I still have the same question. Is this issue reproducible for jdk 9? If not, then we could focus on the 8udev. Otherwise, we have to resolve it in the jdk 9 first.

As I wrote, there are two problems. Those problem are not directly connected. The fix for problem 1), fixes this JVM crash for me. The fix for problem 2) is just a side-effect of the fact that I looked at the code and spotted it. I was still able to reproduce the crash with the fix for problem 2). I don't have enough knowledge of the hotspot code, so it is not clear to me, why clearing the jmethod_id in the deallocate contents() can be wrong. When investigating the JVM crash, I found out that clearing the jmethod_id in the deallocate contents() cleared jmethod_id, which would otherwise caused JVM to crash. In any case, it would great if the fix for problem 2) can be backported to jdk8u-dev - the code is definitely wrong and can cause JVM to crash. It will be in different situation that is described in this bug. Unfortunately the fix for problem 2) is a part of much lager fix JDK-8062116 and jdk8u-dev should have just fix for the obvious bug with b->_methods[i]. It looks to me, that the correct solution should separate bug for problem 2) and fix just for jdk8u-dev.

Tomas, Is this issue reproducible for jdk 9? I see the following part of your suggested fix for method.cpp is already in the jdk 9 (but not in 8u-dev): // During class unloading the methods are cleared, which is different // than freed. void clear_all_methods() { for (JNIMethodBlock* b = this; b != NULL; b = b->_next) { for (int i = 0; i< number_of_methods; i++) { - _methods[i] = NULL; + b->_methods[i] = NULL; } } } @@ -1799,7 +1811,7 @@ int count = 0; for (JNIMethodBlock* b = this; b != NULL; b = b->_next) { for (int i = 0; i< number_of_methods; i++) { - if (_methods[i] != _free_method) count++; + if (b->_methods[i] != _free_method) count++; } } return count; @@ -1871,6 +1883,10 @@ return o; }; It feels like the rest of the changes is not correct. There is the following comment at the only place where the Method::clear_jmethod_ids() is called: // Clear all the JNI handles for methods // These aren't deallocated and are going to look like a leak, but that's // needed because we can't really get rid of jmethodIDs because we don't // know when native code is going to stop using them. The spec says that // they're "invalid" but existing programs likely rely on their being // NULL after class unloading. if (_jmethod_ids != NULL) { Method::clear_jmethod_ids(this); } So that clearing the jmethod_id in the deallocate contents() can be wrong. We may have to double-check with Coleen who made related changes in this area recently.

ILW = H (JVM crash) L (imtermittent, JVMTI only) H (no workaround) = P2

It looks like _methods[i] in JNIMethodBlock can contain obsolete pointer to Method. This will cause crash in Method::checked_resolve_jmethod_id(), when this method invokes (Metadata*)o)->is_method(). There seem to be two problems. 1) Method::deallocate_contents() should clear 'this' from list of Methods in JNIMethodBlock - similarly to clear_all_methods() does it, when class is unloaded. 2) clear_all_methods() does not walk all the linked JNIMethodBlock-s. It just clears the first one several times. See attached patch against JDK8-dev for the fix of above problems.

Detailed steps to reproduce: 1) Run the following code on JDK 8: public class VisualVMTest { public static void main(String[] args){ System.out.print("Press ENTER to exit "); System.console().readLine(); } } 2) Start VisualVM 3) open VisualVMTest process 4) go to Profiler tab 5) click on 'Settings' checkbox 6) select 'Memory settings' tab 7) click 'Record allocation stack traces' checkbox 8) start memory profiling - click on 'Memory' button 9) wait for profiling result 10) wait for some more time 11) click 'Snapshot' button 12) if the JVM does no crash, go to step 10)