-
Bug
-
Resolution: Duplicate
-
P3
-
None
-
12
-
x86_64
-
linux
A DESCRIPTION OF THE PROBLEM :
I can reproduce this with the OpenJDK 12 RPMs on Fedora 30, but from looking at <https://hg.openjdk.java.net/jdk/jdk12/file/06222165c35f/src/java.base/share/classes/java/lang/Class.java> it looks plausible that it is a common issue that Reflection.getCallerClass() returns null when java.lang.Class.newInstance is called from the JNI Invocation API, and that null is propagated to jdk.internal.reflect.Reflection.verifyMemberAccess as parameter currentClass, which dereferences it at <https://hg.openjdk.java.net/jdk/jdk12/file/06222165c35f/src/java.base/share/classes/jdk/internal/reflect/Reflection.java#l130>.
This is known to have been working with older OpenJDK (at least 1.8).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the provided test.cc with `g++ -I/usr/lib/jvm/java-12-openjdk-12.0.0.33-1.ea.1.rolling.fc30.x86_64/include -I/usr/lib/jvm/java-12-openjdk-12.0.0.33-1.ea.1.rolling.fc30.x86_64/include/linux /usr/lib/jvm/java-12-openjdk-12.0.0.33-1.ea.1.rolling.fc30.x86_64/lib/server/libjvm.so test.cc` and run it with `LD_LIBRARY_PATH=/usr/lib/jvm/java-12-openjdk-12.0.0.33-1.ea.1.rolling.fc30.x86_64/lib/server ./a.out`.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
exit 0
ACTUAL -
Exception in thread "main" java.lang.NullPointerException
at java.base/jdk.internal.reflect.Reflection.verifyMemberAccess(Reflection.java:130)
at java.base/java.lang.reflect.AccessibleObject.slowVerifyAccess(AccessibleObject.java:673)
at java.base/java.lang.reflect.AccessibleObject.verifyAccess(AccessibleObject.java:666)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:638)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:490)
at java.base/java.lang.reflect.ReflectAccess.newInstance(ReflectAccess.java:166)
at java.base/jdk.internal.reflect.ReflectionFactory.newInstance(ReflectionFactory.java:404)
at java.base/java.lang.Class.newInstance(Class.java:590)
Aborted
---------- BEGIN SOURCE ----------
#include <cstdlib>
#include "jni.h"
void handleError(JNIEnv * env) {
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
std::abort();
}
}
int main() {
JavaVM * vm;
JNIEnv * env;
JavaVMInitArgs args{JNI_VERSION_1_2, 0, nullptr, true};
if (JNI_CreateJavaVM(&vm, reinterpret_cast<void **>(&env), &args) != JNI_OK) {
std::abort();
}
auto const c1 = env->FindClass("java/lang/Class");
handleError(env);
auto const id = env->GetMethodID(c1, "newInstance", "()Ljava/lang/Object;");
handleError(env);
auto const c2 = env->FindClass("java/lang/Object");
handleError(env);
env->CallObjectMethod(c2, id);
handleError(env);
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Call via JNI the suggested replacement of clazz.getDeclaredConstructor().newInstance() instead of the deprecated java.lang.Class.newInstance().
I can reproduce this with the OpenJDK 12 RPMs on Fedora 30, but from looking at <https://hg.openjdk.java.net/jdk/jdk12/file/06222165c35f/src/java.base/share/classes/java/lang/Class.java> it looks plausible that it is a common issue that Reflection.getCallerClass() returns null when java.lang.Class.newInstance is called from the JNI Invocation API, and that null is propagated to jdk.internal.reflect.Reflection.verifyMemberAccess as parameter currentClass, which dereferences it at <https://hg.openjdk.java.net/jdk/jdk12/file/06222165c35f/src/java.base/share/classes/jdk/internal/reflect/Reflection.java#l130>.
This is known to have been working with older OpenJDK (at least 1.8).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the provided test.cc with `g++ -I/usr/lib/jvm/java-12-openjdk-12.0.0.33-1.ea.1.rolling.fc30.x86_64/include -I/usr/lib/jvm/java-12-openjdk-12.0.0.33-1.ea.1.rolling.fc30.x86_64/include/linux /usr/lib/jvm/java-12-openjdk-12.0.0.33-1.ea.1.rolling.fc30.x86_64/lib/server/libjvm.so test.cc` and run it with `LD_LIBRARY_PATH=/usr/lib/jvm/java-12-openjdk-12.0.0.33-1.ea.1.rolling.fc30.x86_64/lib/server ./a.out`.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
exit 0
ACTUAL -
Exception in thread "main" java.lang.NullPointerException
at java.base/jdk.internal.reflect.Reflection.verifyMemberAccess(Reflection.java:130)
at java.base/java.lang.reflect.AccessibleObject.slowVerifyAccess(AccessibleObject.java:673)
at java.base/java.lang.reflect.AccessibleObject.verifyAccess(AccessibleObject.java:666)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:638)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:490)
at java.base/java.lang.reflect.ReflectAccess.newInstance(ReflectAccess.java:166)
at java.base/jdk.internal.reflect.ReflectionFactory.newInstance(ReflectionFactory.java:404)
at java.base/java.lang.Class.newInstance(Class.java:590)
Aborted
---------- BEGIN SOURCE ----------
#include <cstdlib>
#include "jni.h"
void handleError(JNIEnv * env) {
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
std::abort();
}
}
int main() {
JavaVM * vm;
JNIEnv * env;
JavaVMInitArgs args{JNI_VERSION_1_2, 0, nullptr, true};
if (JNI_CreateJavaVM(&vm, reinterpret_cast<void **>(&env), &args) != JNI_OK) {
std::abort();
}
auto const c1 = env->FindClass("java/lang/Class");
handleError(env);
auto const id = env->GetMethodID(c1, "newInstance", "()Ljava/lang/Object;");
handleError(env);
auto const c2 = env->FindClass("java/lang/Object");
handleError(env);
env->CallObjectMethod(c2, id);
handleError(env);
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Call via JNI the suggested replacement of clazz.getDeclaredConstructor().newInstance() instead of the deprecated java.lang.Class.newInstance().
- duplicates
-
JDK-8221530 Field::get and reflective member access not handling caller = null when invoked by JNI code with no java frames on stack
-
- Resolved
-