8212155: Race condition when posting dynamic_code_generated event leads to JVM crash

Reviewed-by: phh, shade
Backport-of: 64ec8b3e5c8a8d44c92591710d73b833f13c1500
This commit is contained in:
Kerem Kat 2025-09-03 12:12:55 +00:00 committed by Aleksey Shipilev
parent c0a36d8fbe
commit 942d6d0614
4 changed files with 201 additions and 7 deletions

View File

@ -1890,13 +1890,17 @@ void JvmtiExport::post_dynamic_code_generated_while_holding_locks(const char* na
address code_begin, address code_end)
{
// register the stub with the current dynamic code event collector
JvmtiThreadState* state = JvmtiThreadState::state_for(JavaThread::current());
// state can only be NULL if the current thread is exiting which
// should not happen since we're trying to post an event
guarantee(state != NULL, "attempt to register stub via an exiting thread");
JvmtiDynamicCodeEventCollector* collector = state->get_dynamic_code_event_collector();
guarantee(collector != NULL, "attempt to register stub without event collector");
collector->register_stub(name, code_begin, code_end);
// Cannot take safepoint here so do not use state_for to get
// jvmti thread state.
// The collector and/or state might be NULL if JvmtiDynamicCodeEventCollector
// has been initialized while JVMTI_EVENT_DYNAMIC_CODE_GENERATED was disabled.
JvmtiThreadState* state = JavaThread::current()->jvmti_thread_state();
if (state != NULL) {
JvmtiDynamicCodeEventCollector *collector = state->get_dynamic_code_event_collector();
if (collector != NULL) {
collector->register_stub(name, code_begin, code_end);
}
}
}
// Collect all the vm internally allocated objects which are visible to java world

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
public class DynamicCodeGenerated {
static {
System.loadLibrary("DynamicCodeGenerated");
}
public static native void changeEventNotificationMode();
public static void main(String[] args) {
// Try to enable DynamicCodeGenerated event while it is posted
// using JvmtiDynamicCodeEventCollector from VtableStubs::find_stub
Thread t = new Thread(() -> {
changeEventNotificationMode();
});
t.setDaemon(true);
t.start();
for (int i = 0; i < 2000; i++) {
new Thread(() -> {
String result = "string" + System.currentTimeMillis();
// Keep a reference to result
if (result.hashCode() == System.currentTimeMillis()) {
// Shouldn't happen
return;
}
}).start();
}
}
}

View File

@ -0,0 +1,82 @@
#!/bin/sh
# Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
# @test DynamicCodeGeneratedTest.sh
# @bug 8212155
# @summary Test concurrent enabling and posting of DynamicCodeGenerated events.
# @run shell DynamicCodeGeneratedTest.sh
if [ "$TESTSRC" = "" ]
then TESTSRC=.
fi
if [ "$TESTJAVA" = "" ]
then
PARENT=$(dirname $(which java))
TESTJAVA=$(dirname $PARENT)
echo "TESTJAVA not set, selecting " $TESTJAVA
echo "If this is incorrect, try setting the variable manually."
fi
# set platform-dependent variables
OS=$(uname -s)
case "$OS" in
Linux )
ARCHFLAG=
$TESTJAVA/bin/java -version 2>&1 | grep '64-Bit' > /dev/null
if [ $? -eq '0' ]
then
ARCH="amd64"
else
ARCH="i386"
ARCHFLAG="-m32 -march=i386"
fi
;;
* )
echo "Test passed, unrecognized system."
exit 0;
;;
esac
echo "OS-ARCH is" linux-$ARCH
$TESTJAVA/jre/bin/java -fullversion 2>&1
which gcc >/dev/null 2>&1
if [ "$?" -ne '0' ]
then
echo "No C compiler found. Test passed."
exit 0
fi
JAVA=$TESTJAVA/jre/bin/java
JAVAC=$TESTJAVA/bin/javac
JAVAH=$TESTJAVA/bin/javah
$JAVAC -d . $TESTSRC/DynamicCodeGenerated.java
$JAVAH -jni -classpath . -d . DynamicCodeGenerated
gcc --shared $ARCHFLAG -fPIC -O -I$TESTJAVA/include -I$TESTJAVA/include/linux -I. -o libDynamicCodeGenerated.so $TESTSRC/libDynamicCodeGenerated.cpp
LD_LIBRARY_PATH=. $JAVA -classpath . -agentlib:DynamicCodeGenerated DynamicCodeGenerated
exit $?

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <string.h>
#include <jvmti.h>
static jvmtiEnv* jvmti = NULL;
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT
void JNICALL Java_DynamicCodeGenerated_changeEventNotificationMode(JNIEnv* jni, jclass cls) {
while (true) {
jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
jvmti->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
}
}
#ifdef __cplusplus
}
#endif
void JNICALL DynamicCodeGenerated(jvmtiEnv* jvmti, const char* name, const void* address, jint length) {
}
jint Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
vm->GetEnv((void**)&jvmti, JVMTI_VERSION_1_0);
jvmtiEventCallbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.DynamicCodeGenerated = DynamicCodeGenerated;
jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
return 0;
}