8345422: Fix JNI Checker "in native method" warnings in the debug agent and debugger tests

8344804: Test serviceability/jdwp/AllModulesCommandTest.java times out after JNI check warning

Reviewed-by: amenkov, dholmes
This commit is contained in:
Chris Plummer 2024-12-05 03:33:50 +00:00
parent 67a7b0049d
commit 77cfcee8a1
9 changed files with 85 additions and 45 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2024, 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
@ -30,7 +30,7 @@
static jclass jlM(JNIEnv *env) {
return findClass(env, "Ljava/lang/Module;");
return findClass(env, "java/lang/Module");
}
static jboolean
@ -50,6 +50,11 @@ getName(PacketInputStream *in, PacketOutputStream *out)
return JNI_TRUE;
}
namestr = (jstring)JNI_FUNC_PTR(env, CallObjectMethod) (env, module, method);
if (JNI_FUNC_PTR(env,ExceptionCheck)(env)) {
JNI_FUNC_PTR(env,ExceptionClear)(env); // keep -Xcheck:jni happy
ERROR_MESSAGE(("JNI Exception occurred calling Module.getName()"));
EXIT_ERROR(AGENT_ERROR_JNI_EXCEPTION, NULL);
}
if (namestr != NULL) {
name = (char*)JNI_FUNC_PTR(env, GetStringUTFChars)(env, namestr, NULL);
} else {
@ -78,6 +83,11 @@ getClassLoader(PacketInputStream *in, PacketOutputStream *out)
return JNI_TRUE;
}
loader = JNI_FUNC_PTR(env, CallObjectMethod) (env, module, method);
if (JNI_FUNC_PTR(env,ExceptionCheck)(env)) {
JNI_FUNC_PTR(env,ExceptionClear)(env); // keep -Xcheck:jni happy
ERROR_MESSAGE(("JNI Exception occurred calling ClassLoader.getClassLoader()"));
EXIT_ERROR(AGENT_ERROR_JNI_EXCEPTION, NULL);
}
(void)outStream_writeObjectRef(env, out, loader);
return JNI_TRUE;

View File

@ -681,23 +681,14 @@ event_callback(JNIEnv *env, EventInfo *evinfo)
bagDestroyBag(eventBag);
}
/* Always restore any exception that was set beforehand. If
* there is a pending async exception, StopThread will be
* called from threadControl_onEventHandlerExit immediately
* below. Depending on VM implementation and state, the async
* exception might immediately overwrite the currentException,
* or it might be delayed until later. */
if (currentException != NULL) {
JNI_FUNC_PTR(env,Throw)(env, currentException);
} else {
JNI_FUNC_PTR(env,ExceptionClear)(env);
}
/* Clear any exception thrown while handling the event. */
JNI_FUNC_PTR(env,ExceptionClear)(env);
/*
* Release thread resources and perform any delayed operations.
*/
if (thread != NULL) {
threadControl_onEventHandlerExit(evinfo->ei, thread, eventBag);
threadControl_onEventHandlerExit(evinfo->ei, thread, eventBag, currentException);
}
}

View File

@ -338,6 +338,22 @@ invoker_requestInvoke(jbyte invokeType, jbyte options, jint id,
return error;
}
static void
saveGlobalRefHelper(JNIEnv *env, jobject obj, jobject *pobj)
{
// In order to keep -Xcheck:jni happy, we have to clear any pending
// exception before calling saveGlobalRef(). We also need to restore
// it for the caller of this function.
jthrowable exception = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
if (exception != NULL) {
JNI_FUNC_PTR(env,ExceptionClear)(env);
}
saveGlobalRef(env, obj, pobj);
if (exception != NULL) {
JNI_FUNC_PTR(env,Throw)(env, exception);
}
}
static void
invokeConstructor(JNIEnv *env, InvokeRequest *request)
{
@ -349,7 +365,7 @@ invokeConstructor(JNIEnv *env, InvokeRequest *request)
request->arguments);
request->returnValue.l = NULL;
if (object != NULL) {
saveGlobalRef(env, object, &(request->returnValue.l));
saveGlobalRefHelper(env, object, &(request->returnValue.l));
}
}
@ -367,7 +383,7 @@ invokeStatic(JNIEnv *env, InvokeRequest *request)
request->arguments);
request->returnValue.l = NULL;
if (object != NULL) {
saveGlobalRef(env, object, &(request->returnValue.l));
saveGlobalRefHelper(env, object, &(request->returnValue.l));
}
return;
}
@ -455,7 +471,7 @@ invokeVirtual(JNIEnv *env, InvokeRequest *request)
request->arguments);
request->returnValue.l = NULL;
if (object != NULL) {
saveGlobalRef(env, object, &(request->returnValue.l));
saveGlobalRefHelper(env, object, &(request->returnValue.l));
}
return;
}
@ -545,7 +561,7 @@ invokeNonvirtual(JNIEnv *env, InvokeRequest *request)
request->arguments);
request->returnValue.l = NULL;
if (object != NULL) {
saveGlobalRef(env, object, &(request->returnValue.l));
saveGlobalRefHelper(env, object, &(request->returnValue.l));
}
return;
}

View File

@ -2141,7 +2141,7 @@ doPendingTasks(JNIEnv *env, jthread thread, int pendingInterrupt, jobject pendin
void
threadControl_onEventHandlerExit(EventIndex ei, jthread thread,
struct bag *eventBag)
struct bag *eventBag, jobject currentException)
{
ThreadNode *node;
JNIEnv *env = getEnv();
@ -2178,6 +2178,17 @@ threadControl_onEventHandlerExit(EventIndex ei, jthread thread,
// locks when doing that. Thus we got all our node updates done first
// and can now exit the threadLock.
debugMonitorExit(threadLock);
if (currentException != NULL) {
// We need to rethrow the exception that was current when we received the
// JVMTI event. If there is a pending async exception, StopThread will be
// called from doPendingTasks() immediately below. Depending on the VM
// implementation and state, the async exception might immediately overwrite
// the currentException, or it might be delayed until later.
//
// Note in order the keep the JNI Checker happy, we had to delay doing this
// until now. Otherwise there are complaints when JNI IsVirtualThread is called.
JNI_FUNC_PTR(env,Throw)(env, currentException);
}
doPendingTasks(env, thread, pendingInterrupt, pendingStop);
if (pendingStop != NULL) {
tossGlobalRef(env, &pendingStop);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024, 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
@ -41,8 +41,7 @@ void threadControl_onDisconnect(void);
jvmtiError threadControl_popFrames(jthread thread, FrameNumber fnum);
struct bag *threadControl_onEventHandlerEntry(jbyte sessionID, EventInfo *evinfo, jobject currentException);
void threadControl_onEventHandlerExit(EventIndex ei, jthread thread, struct bag *);
void threadControl_onEventHandlerExit(EventIndex ei, jthread thread, struct bag *, jobject currentException);
jvmtiError threadControl_suspendThread(jthread thread, jboolean deferred);
jvmtiError threadControl_resumeThread(jthread thread, jboolean do_unblock);

View File

@ -101,13 +101,10 @@ findClass(JNIEnv *env, const char * name)
EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"findClass name");
}
x = JNI_FUNC_PTR(env,FindClass)(env, name);
if (x == NULL) {
ERROR_MESSAGE(("JDWP Can't find class %s", name));
EXIT_ERROR(AGENT_ERROR_NULL_POINTER,NULL);
}
if ( JNI_FUNC_PTR(env,ExceptionCheck)(env) ) {
ERROR_MESSAGE(("JDWP Exception occurred finding class %s", name));
EXIT_ERROR(AGENT_ERROR_NULL_POINTER,NULL);
JNI_FUNC_PTR(env,ExceptionClear)(env); // keep -Xcheck:jni happy
ERROR_MESSAGE(("JNI Exception occurred finding class %s", name));
EXIT_ERROR(AGENT_ERROR_JNI_EXCEPTION,NULL);
}
return x;
}
@ -130,15 +127,11 @@ getMethod(JNIEnv *env, jclass clazz, const char * name, const char *signature)
EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getMethod signature");
}
method = JNI_FUNC_PTR(env,GetMethodID)(env, clazz, name, signature);
if (method == NULL) {
ERROR_MESSAGE(("JDWP Can't find method %s with signature %s",
name, signature));
EXIT_ERROR(AGENT_ERROR_NULL_POINTER,NULL);
}
if ( JNI_FUNC_PTR(env,ExceptionCheck)(env) ) {
ERROR_MESSAGE(("JDWP Exception occurred finding method %s with signature %s",
name, signature));
EXIT_ERROR(AGENT_ERROR_NULL_POINTER,NULL);
JNI_FUNC_PTR(env,ExceptionClear)(env); // keep -Xcheck:jni happy
ERROR_MESSAGE(("JNI Exception occurred finding method %s with signature %s",
name, signature));
EXIT_ERROR(AGENT_ERROR_JNI_EXCEPTION,NULL);
}
return method;
}
@ -161,15 +154,11 @@ getStaticMethod(JNIEnv *env, jclass clazz, const char * name, const char *signat
EXIT_ERROR(AGENT_ERROR_ILLEGAL_ARGUMENT,"getStaticMethod signature");
}
method = JNI_FUNC_PTR(env,GetStaticMethodID)(env, clazz, name, signature);
if (method == NULL) {
ERROR_MESSAGE(("JDWP Can't find method %s with signature %s",
name, signature));
EXIT_ERROR(AGENT_ERROR_NULL_POINTER,NULL);
}
if ( JNI_FUNC_PTR(env,ExceptionCheck)(env) ) {
JNI_FUNC_PTR(env,ExceptionClear)(env); // keep -Xcheck:jni happy
ERROR_MESSAGE(("JDWP Exception occurred finding method %s with signature %s",
name, signature));
EXIT_ERROR(AGENT_ERROR_NULL_POINTER,NULL);
name, signature));
EXIT_ERROR(AGENT_ERROR_JNI_EXCEPTION,NULL);
}
return method;
}

View File

@ -116,6 +116,7 @@ Java_nsk_share_ReferringObject_createJNILocalReferenceNative(JNIEnv *env,
env->ThrowNew(
env->FindClass("nsk/share/TestJNIError"),
"NewLocalRef return null");
return;
}
klass = env->GetObjectClass(createWicket);
@ -123,8 +124,11 @@ Java_nsk_share_ReferringObject_createJNILocalReferenceNative(JNIEnv *env,
// notify another thread that JNI local reference has been created
env->CallVoidMethod(createWicket,
env->GetMethodID(klass, "unlock", "()V"));
if (env->ExceptionCheck()) {
return;
}
// wait till JNI local reference can be released (it will heppen then we will leave the method)
// wait till JNI local reference can be released (it will happen then we will leave the method)
env->CallVoidMethod(deleteWicket,
env->GetMethodID(klass, "waitFor", "()V"));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2024, 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
@ -33,6 +33,10 @@ static void logMessage(JNIEnv *env, jobject thisObject, jstring message)
env->CallVoidMethod(thisObject,
env->GetMethodID(klass, "log", "(Ljava/lang/String;)V"),
message);
if (env->ExceptionOccurred()) {
env->ExceptionDescribe();
env->FatalError("ERROR: Failed to log message.");
}
}
JNIEXPORT void JNICALL

View File

@ -66,6 +66,7 @@ This method executes JNI analog for following Java code:
env->ThrowNew(
env->FindClass("nsk/share/TestJNIError"),
"MonitorEnter return non-zero");
return;
}
thisObjectClass = env->GetObjectClass(thisObject);
@ -78,6 +79,9 @@ This method executes JNI analog for following Java code:
env->CallVoidMethod(wicketObject,
env->GetMethodID(wicketClass, "unlockAll", "()V"));
if (env->ExceptionOccurred()) {
return;
}
// step2.waitFor()
field = env->GetFieldID(thisObjectClass, "step2", "Lnsk/share/Wicket;");
@ -85,6 +89,9 @@ This method executes JNI analog for following Java code:
env->CallVoidMethod(wicketObject,
env->GetMethodID(wicketClass, "waitFor", "()V"));
if (env->ExceptionOccurred()) {
return;
}
// readyWicket.unlock()
field = env->GetFieldID(thisObjectClass, "readyWicket", "Lnsk/share/Wicket;");
@ -92,6 +99,9 @@ This method executes JNI analog for following Java code:
env->CallVoidMethod(wicketObject,
env->GetMethodID(wicketClass, "unlock", "()V"));
if (env->ExceptionOccurred()) {
return;
}
// inner.lock()
field = env->GetFieldID(thisObjectClass, "inner", "Lnsk/share/locks/DeadlockLocker;");
@ -100,8 +110,14 @@ This method executes JNI analog for following Java code:
env->CallVoidMethod(innerObject,
env->GetMethodID(deadlockLockerClass, "lock", "()V"));
if (env->ExceptionOccurred()) {
return;
}
success = env->MonitorExit(thisObject);
if (env->ExceptionOccurred()) {
return;
}
if (success != 0)
{