8336663: [JVMCI] VM Crash on ZGC due to incompatible handle returned by HotSpotJVMCIRuntime#getJObjectValue

Reviewed-by: dnsimon, never
This commit is contained in:
Tomas Zezula 2024-07-26 14:42:24 +00:00
parent 5ff7c57f9f
commit 3abe8a6e5e
3 changed files with 37 additions and 13 deletions

View File

@ -94,6 +94,12 @@ static void requireInHotSpot(const char* caller, JVMCI_TRAPS) {
}
}
static void requireNotInHotSpot(const char* caller, JVMCI_TRAPS) {
if (JVMCIENV->is_hotspot()) {
JVMCI_THROW_MSG(IllegalStateException, err_msg("Cannot call %s from HotSpot", caller));
}
}
class JVMCITraceMark : public StackObj {
const char* _msg;
public:
@ -702,6 +708,17 @@ C2V_VMENTRY_NULL(jobject, lookupJClass, (JNIEnv* env, jobject, jlong jclass_valu
return JVMCIENV->get_jobject(result);
C2V_END
C2V_VMENTRY_0(jlong, getJObjectValue, (JNIEnv* env, jobject, jobject constant_jobject))
requireNotInHotSpot("getJObjectValue", JVMCI_CHECK_0);
if (!THREAD->has_last_Java_frame()) {
JVMCI_THROW_MSG_0(IllegalStateException, err_msg("Cannot call getJObjectValue without Java frame anchor"));
}
JVMCIObject constant = JVMCIENV->wrap(constant_jobject);
Handle constant_value = JVMCIENV->asConstant(constant, JVMCI_CHECK_0);
jobject jni_handle = JNIHandles::make_local(THREAD, constant_value());
return reinterpret_cast<jlong>(jni_handle);
C2V_END
C2V_VMENTRY_NULL(jobject, getUncachedStringInPool, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint index))
constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
constantTag tag = cp->tag_at(index);
@ -3254,6 +3271,7 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "shouldInlineMethod", CC "(" HS_METHOD2 ")Z", FN_PTR(shouldInlineMethod)},
{CC "lookupType", CC "(" STRING HS_KLASS2 "IZ)" HS_RESOLVED_TYPE, FN_PTR(lookupType)},
{CC "lookupJClass", CC "(J)" HS_RESOLVED_TYPE, FN_PTR(lookupJClass)},
{CC "getJObjectValue", CC "(" OBJECTCONSTANT ")J", FN_PTR(getJObjectValue)},
{CC "getArrayType", CC "(C" HS_KLASS2 ")" HS_KLASS, FN_PTR(getArrayType)},
{CC "lookupClass", CC "(" CLASS ")" HS_RESOLVED_TYPE, FN_PTR(lookupClass)},
{CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL2 "II)" STRING, FN_PTR(lookupNameInPool)},

View File

@ -289,6 +289,12 @@ final class CompilerToVM {
native HotSpotResolvedJavaType lookupJClass(long jclass);
/**
* Gets the {@code jobject} value wrapped by {@code peerObject}.
* Must not be called if {@link Services#IS_IN_NATIVE_IMAGE} is {@code false}.
*/
native long getJObjectValue(HotSpotObjectConstantImpl peerObject);
/**
* Resolves the entry at index {@code cpi} in {@code constantPool} to an interned String object.
*

View File

@ -925,23 +925,23 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
}
/**
* Gets the {@code jobject} value wrapped by {@code peerObject}. The returned "naked" value is
* only valid as long as {@code peerObject} is valid. Note that the latter may be shorter than
* the lifetime of {@code peerObject}. As such, this method should only be used to pass an
* object parameter across a JNI call from the JVMCI shared library to HotSpot. This method must
* only be called from within the JVMCI shared library.
* Gets the {@code jobject} value wrapped by {@code peerObject}. The returned value is
* a JNI local reference whose lifetime is scoped by the nearest Java caller (from
* HotSpot's perspective). You can use {@code PushLocalFrame} and {@code PopLocalFrame} to
* shorten the lifetime of the reference. The current thread's state must be
* {@code _thread_in_native}. A call from the JVMCI shared library (e.g. libgraal) is in such
* a state.
*
* @param peerObject a reference to an object in the peer runtime
* @return the {@code jobject} value wrapped by {@code peerObject}
* @param peerObject a reference to an object in the HotSpot heap
* @return the {@code jobject} value unpacked from {@code peerObject}
* @throws IllegalArgumentException if the current runtime is not the JVMCI shared library or
* {@code peerObject} is not a peer object reference
* {@code peerObject} is not a HotSpot heap object reference
* @throws IllegalStateException if not called from within the JVMCI shared library
* or if there is no Java caller frame on the stack
* (i.e., JavaThread::has_last_Java_frame returns false)
*/
public long getJObjectValue(HotSpotObjectConstant peerObject) {
if (peerObject instanceof IndirectHotSpotObjectConstantImpl) {
IndirectHotSpotObjectConstantImpl remote = (IndirectHotSpotObjectConstantImpl) peerObject;
return remote.getHandle();
}
throw new IllegalArgumentException("Cannot get jobject value for " + peerObject + " (" + peerObject.getClass().getName() + ")");
return compilerToVm.getJObjectValue((HotSpotObjectConstantImpl)peerObject);
}
@Override