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.
jni_exit() should box and unbox the naked oop into a handle over the call to revoke bias. FastHashCode() serves as good model.
Comments
See https://jbs.oracle.com/bugs/browse/JDK-8004902 for the webrevs used during Code Review Round [012] for this fix.
17-01-2013
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