Skip to content

Commit 942d6d0

Browse files
Kerem Katshipilev
authored andcommitted
8212155: Race condition when posting dynamic_code_generated event leads to JVM crash
Reviewed-by: phh, shade Backport-of: 64ec8b3e5c8a8d44c92591710d73b833f13c1500
1 parent c0a36d8 commit 942d6d0

File tree

4 files changed

+201
-7
lines changed

4 files changed

+201
-7
lines changed

hotspot/src/share/vm/prims/jvmtiExport.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1890,13 +1890,17 @@ void JvmtiExport::post_dynamic_code_generated_while_holding_locks(const char* na
18901890
address code_begin, address code_end)
18911891
{
18921892
// register the stub with the current dynamic code event collector
1893-
JvmtiThreadState* state = JvmtiThreadState::state_for(JavaThread::current());
1894-
// state can only be NULL if the current thread is exiting which
1895-
// should not happen since we're trying to post an event
1896-
guarantee(state != NULL, "attempt to register stub via an exiting thread");
1897-
JvmtiDynamicCodeEventCollector* collector = state->get_dynamic_code_event_collector();
1898-
guarantee(collector != NULL, "attempt to register stub without event collector");
1899-
collector->register_stub(name, code_begin, code_end);
1893+
// Cannot take safepoint here so do not use state_for to get
1894+
// jvmti thread state.
1895+
// The collector and/or state might be NULL if JvmtiDynamicCodeEventCollector
1896+
// has been initialized while JVMTI_EVENT_DYNAMIC_CODE_GENERATED was disabled.
1897+
JvmtiThreadState* state = JavaThread::current()->jvmti_thread_state();
1898+
if (state != NULL) {
1899+
JvmtiDynamicCodeEventCollector *collector = state->get_dynamic_code_event_collector();
1900+
if (collector != NULL) {
1901+
collector->register_stub(name, code_begin, code_end);
1902+
}
1903+
}
19001904
}
19011905

19021906
// Collect all the vm internally allocated objects which are visible to java world
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
public class DynamicCodeGenerated {
25+
static {
26+
System.loadLibrary("DynamicCodeGenerated");
27+
}
28+
public static native void changeEventNotificationMode();
29+
30+
public static void main(String[] args) {
31+
// Try to enable DynamicCodeGenerated event while it is posted
32+
// using JvmtiDynamicCodeEventCollector from VtableStubs::find_stub
33+
Thread t = new Thread(() -> {
34+
changeEventNotificationMode();
35+
});
36+
t.setDaemon(true);
37+
t.start();
38+
39+
for (int i = 0; i < 2000; i++) {
40+
new Thread(() -> {
41+
String result = "string" + System.currentTimeMillis();
42+
43+
// Keep a reference to result
44+
if (result.hashCode() == System.currentTimeMillis()) {
45+
// Shouldn't happen
46+
return;
47+
}
48+
}).start();
49+
}
50+
}
51+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/bin/sh
2+
3+
# Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
4+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
#
6+
# This code is free software; you can redistribute it and/or modify it
7+
# under the terms of the GNU General Public License version 2 only, as
8+
# published by the Free Software Foundation.
9+
#
10+
# This code is distributed in the hope that it will be useful, but WITHOUT
11+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
# version 2 for more details (a copy is included in the LICENSE file that
14+
# accompanied this code).
15+
#
16+
# You should have received a copy of the GNU General Public License version
17+
# 2 along with this work; if not, write to the Free Software Foundation,
18+
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19+
#
20+
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21+
# or visit www.oracle.com if you need additional information or have any
22+
# questions.
23+
24+
# @test DynamicCodeGeneratedTest.sh
25+
# @bug 8212155
26+
# @summary Test concurrent enabling and posting of DynamicCodeGenerated events.
27+
# @run shell DynamicCodeGeneratedTest.sh
28+
29+
if [ "$TESTSRC" = "" ]
30+
then TESTSRC=.
31+
fi
32+
33+
if [ "$TESTJAVA" = "" ]
34+
then
35+
PARENT=$(dirname $(which java))
36+
TESTJAVA=$(dirname $PARENT)
37+
echo "TESTJAVA not set, selecting " $TESTJAVA
38+
echo "If this is incorrect, try setting the variable manually."
39+
fi
40+
41+
# set platform-dependent variables
42+
OS=$(uname -s)
43+
case "$OS" in
44+
Linux )
45+
ARCHFLAG=
46+
$TESTJAVA/bin/java -version 2>&1 | grep '64-Bit' > /dev/null
47+
if [ $? -eq '0' ]
48+
then
49+
ARCH="amd64"
50+
else
51+
ARCH="i386"
52+
ARCHFLAG="-m32 -march=i386"
53+
fi
54+
;;
55+
* )
56+
echo "Test passed, unrecognized system."
57+
exit 0;
58+
;;
59+
esac
60+
61+
echo "OS-ARCH is" linux-$ARCH
62+
$TESTJAVA/jre/bin/java -fullversion 2>&1
63+
64+
which gcc >/dev/null 2>&1
65+
if [ "$?" -ne '0' ]
66+
then
67+
echo "No C compiler found. Test passed."
68+
exit 0
69+
fi
70+
71+
JAVA=$TESTJAVA/jre/bin/java
72+
JAVAC=$TESTJAVA/bin/javac
73+
JAVAH=$TESTJAVA/bin/javah
74+
75+
$JAVAC -d . $TESTSRC/DynamicCodeGenerated.java
76+
$JAVAH -jni -classpath . -d . DynamicCodeGenerated
77+
78+
gcc --shared $ARCHFLAG -fPIC -O -I$TESTJAVA/include -I$TESTJAVA/include/linux -I. -o libDynamicCodeGenerated.so $TESTSRC/libDynamicCodeGenerated.cpp
79+
80+
LD_LIBRARY_PATH=. $JAVA -classpath . -agentlib:DynamicCodeGenerated DynamicCodeGenerated
81+
82+
exit $?
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
#include <string.h>
25+
#include <jvmti.h>
26+
27+
static jvmtiEnv* jvmti = NULL;
28+
29+
#ifdef __cplusplus
30+
extern "C" {
31+
#endif
32+
33+
JNIEXPORT
34+
void JNICALL Java_DynamicCodeGenerated_changeEventNotificationMode(JNIEnv* jni, jclass cls) {
35+
while (true) {
36+
jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
37+
jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
38+
}
39+
}
40+
41+
#ifdef __cplusplus
42+
}
43+
#endif
44+
45+
void JNICALL DynamicCodeGenerated(jvmtiEnv* jvmti, const char* name, const void* address, jint length) {
46+
47+
}
48+
49+
jint Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
50+
vm->GetEnv((void**)&jvmti, JVMTI_VERSION_1_0);
51+
jvmtiEventCallbacks callbacks;
52+
memset(&callbacks, 0, sizeof(callbacks));
53+
callbacks.DynamicCodeGenerated = DynamicCodeGenerated;
54+
jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
55+
56+
return 0;
57+
}

0 commit comments

Comments
 (0)