JDK-6444286 : Possible naked oop related to biased locking revocation safepoint in jni_exit()
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2006-06-28
  • Updated: 2014-06-26
  • Resolved: 2013-01-22
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.
JDK 7 JDK 8 Other
7u40Fixed 8Fixed hs24Fixed
jni_exit() should box and unbox the naked oop into a handle over the call to revoke bias.  FastHashCode() serves as good model.

See https://jbs.oracle.com/bugs/browse/JDK-8004902 for the webrevs used during Code Review Round [012] for this fix.

Testing the fix for this bug requires the proper alignment of the stars, the moon and a few of the planets: - -XX:+UseBiasedLocking option - a JNI MonitorExit() call on an appropriately biased Java object - a GC operation that moves the appropriately biased Java object in such a way that access to the memory that used to contain that Java object now blows up The last item above is the tricky one. It is entirely possible for GC to relocate the appropriately biased Java object and for the subsequent access of the memory that used to contain that Java object to _not_ blow up. An alternative is to create a test that exercises the code path in question: :::::::::::::: UnsafeJNIMonitorTest.java :::::::::::::: // // Run this test with the following command: // // $JAVA_HOME/fastdebug/bin/java \ // -XX:+UseBiasedLocking \ // -Xbootclasspath/p:. \ // UnsafeJNIMonitorTest // import sun.misc.Unsafe; public class UnsafeJNIMonitorTest { private static final Unsafe unsafe = Unsafe.getUnsafe(); public static void main(String[] args) { System.out.println("Hello from UnsafeJNIMonitorTest!"); Object dummy = new Object(); unsafe.monitorEnter(dummy); System.out.println("Entered dummy monitor."); unsafe.monitorExit(dummy); System.out.println("Exited dummy monitor."); } } :::::::::::::: doit.sh :::::::::::::: set -x $JAVA_HOME/bin/java \ "$@" \ -XX:+UseBiasedLocking \ -Xbootclasspath/p:. \ UnsafeJNIMonitorTest Now you need a VM with the following modifications: diff -r 97ee8abd6ab2 src/share/vm/runtime/biasedLocking.cpp --- a/src/share/vm/runtime/biasedLocking.cpp Wed Jan 09 12:10:25 2013 -0800 +++ b/src/share/vm/runtime/biasedLocking.cpp Thu Jan 10 16:52:31 2013 -0700 @@ -527,6 +527,12 @@ BiasedLocking::Condition BiasedLocking:: BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) { assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint"); +if (Threads::number_of_threads() > 0) { +// don't do the dummy safepoint until main is up and running +VM_ForceSafepoint dummy_safepoint; +VMThread::execute(&dummy_safepoint); +} + // We can revoke the biases of anonymously-biased objects // efficiently enough that we should not cause these revocations to // update the heuristics because doing so may cause unwanted bulk diff -r 97ee8abd6ab2 src/share/vm/runtime/synchronizer.cpp --- a/src/share/vm/runtime/synchronizer.cpp Wed Jan 09 12:10:25 2013 -0800 +++ b/src/share/vm/runtime/synchronizer.cpp Thu Jan 10 16:52:31 2013 -0700 @@ -333,6 +333,7 @@ void ObjectSynchronizer::jni_exit(oop ob void ObjectSynchronizer::jni_exit(oop obj, Thread* THREAD) { TEVENT (jni_exit) ; if (UseBiasedLocking) { +No_Safepoint_Verifier nsv; BiasedLocking::revoke_and_rebias(obj, false, THREAD); } assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now"); The change in src/share/vm/runtime/synchronizer.cpp simply add a No_Safepoint_Verifier helper object right before the questionable call to BiasedLocking::revoke_and_rebias(obj, false, THREAD); The change in src/share/vm/runtime/biasedLocking.cpp simply forces a safepoint to happen in BiasedLocking::revoke_and_rebias() once the VM has gotten up to the point where the main thread is running. If you look at the logic in BiasedLocking::revoke_and_rebias(), you'll see there are many different paths that can cause a safepoint. Here's the output when you run the test: + /work/local/jdk/1.8.0/solaris-x64/bin/java -client_bh_hsx_rt_latest_exp_dcubed-fast -showversion -XX:+UseBiasedLocking -Xbootclasspath/p:. UnsafeJNIMonitorTest Java HotSpot(TM) Client VM warning: Thread holding lock at safepoint that vm can block on: MethodCompileQueue_lock java version "1.8.0-ea" Java(TM) SE Runtime Environment (build 1.8.0-ea-b71) Java HotSpot(TM) Client VM (build 25.0-b15-bh_hsx_rt_latest_exp_dcubed-product-fastdebug, mixed mode) Hello from UnsafeJNIMonitorTest! Entered dummy monitor. # To suppress the following error report, specify this argument # after -XX: or in .hotspotrc: SuppressErrorAt=/thread.cpp:911 # # A fatal error has been detected by the Java Runtime Environment: # # Internal Error (/work/shared/bug_hunt/hsx_rt_latest/exp/src/share/vm/runtime/thread.cpp:911), pid=19176, tid=2 # fatal error: Possible safepoint reached by thread that does not allow it # # JRE version: Java(TM) SE Runtime Environment (8.0-b71) (build 1.8.0-ea-b71) # Java VM: Java HotSpot(TM) Client VM (25.0-b15-bh_hsx_rt_latest_exp_dcubed-product-fastdebug mixed mode solaris-x86 ) # Core dump written. Default location: /work/shared/bugs/6444286/core or core.19176 # # An error report file with more information is saved as: # /work/shared/bugs/6444286/hs_err_pid19176.log # # If you would like to submit a bug report, please visit: # http://bugreport.sun.com/bugreport/crash.jsp # Current thread is 2 Dumping core ... Abort - core dumped And here's the crashing thread's stack: --------------- T H R E A D --------------- Current thread (0x0806c000): JavaThread "main" [_thread_in_vm, id=2, stack(0xfc eef000,0xfcf3f000)] Stack: [0xfceef000,0xfcf3f000], sp=0xfcf3df00, free space=315k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) V [libjvm.so+0x1591cc9] void VMError::report(outputStream*)+0x92d V [libjvm.so+0x1592f4e] void VMError::report_and_die()+0x57a V [libjvm.so+0x78a8bf] void report_fatal(const char*,int,const char*)+0x56f V [libjvm.so+0x148f252] void Thread::check_for_valid_safepoint_state(bool)+0x1 56 V [libjvm.so+0x15bcafe] void VMThread::execute(VM_Operation*)+0x1f6 V [libjvm.so+0x2f2796] BiasedLocking::Condition BiasedLocking::revoke_and_rebi as(Handle,bool,Thread*)+0x66 V [libjvm.so+0x14071fd] void ObjectSynchronizer::jni_exit(oop,Thread*)+0x189 V [libjvm.so+0x1535c62] Unsafe_MonitorExit+0x4fa j sun.misc.Unsafe.monitorExit(Ljava/lang/Object;)V+0 j UnsafeJNIMonitorTest.main([Ljava/lang/String;)V+35

EVALUATION should fix.