From 64ec8b3e5c8a8d44c92591710d73b833f13c1500 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik <lmesnik@openjdk.org> Date: Fri, 4 Jun 2021 17:22:01 +0000 Subject: [PATCH] 8212155: Race condition when posting dynamic_code_generated event leads to JVM crash Reviewed-by: sspitsyn, dcubed --- src/hotspot/share/prims/jvmtiExport.cpp | 14 +++-- .../DynamicCodeGeneratedTest.java | 57 +++++++++++++++++++ .../libDynamicCodeGenerated.cpp | 57 +++++++++++++++++++ 3 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 test/hotspot/jtreg/serviceability/jvmti/DynamicCodeGenerated/DynamicCodeGeneratedTest.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/DynamicCodeGenerated/libDynamicCodeGenerated.cpp diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index b3951a913f1..dd0f1885c8b 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -2289,13 +2289,15 @@ void JvmtiExport::post_dynamic_code_generated_while_holding_locks(const char* na // register the stub with the current dynamic code event collector // 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(); - // 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); + 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 diff --git a/test/hotspot/jtreg/serviceability/jvmti/DynamicCodeGenerated/DynamicCodeGeneratedTest.java b/test/hotspot/jtreg/serviceability/jvmti/DynamicCodeGenerated/DynamicCodeGeneratedTest.java new file mode 100644 index 00000000000..649fb319102 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/DynamicCodeGenerated/DynamicCodeGeneratedTest.java @@ -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. + */ + +/* + * @test + * @bug 8212155 + * @summary Test concurrent enabling and posting of DynamicCodeGenerated events. + * @requires vm.jvmti + * @library /test/lib + * @run main/othervm/native -agentlib:DynamicCodeGenerated DynamicCodeGeneratedTest + */ + +import java.lang.ref.Reference; + +public class DynamicCodeGeneratedTest { + 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(); + Reference.reachabilityFence(result); + }).start(); + } + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/DynamicCodeGenerated/libDynamicCodeGenerated.cpp b/test/hotspot/jtreg/serviceability/jvmti/DynamicCodeGenerated/libDynamicCodeGenerated.cpp new file mode 100644 index 00000000000..45c98dcba32 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/DynamicCodeGenerated/libDynamicCodeGenerated.cpp @@ -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_DynamicCodeGeneratedTest_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; +}