Kaydet (Commit) 27c6d1db authored tarafından Stephan Bergmann's avatar Stephan Bergmann

Avoid calling java.lang.Class.newInstance()

For one, it is deprecated since Java 9, and for another it causes a
NullPointerException when called from the JNI Invocation API (i.e., without a
Java caller frame) at least with some Java 12.

(Found when doing a test build with Java 12 and JAVA_SOURCE/TARGET_VER
explicitly configured as 7 with d365f363 "Allow
to pass JAVA_SOURCE/TARGET_VER into configure".)

I have entered information about the NullPointerException at
<https://bugreport.java.com/bugreport/start_form.do>, but haven't heard back
yet, so duplicate that information here:

Issue Type:
> Bug

Component:
> Core Libraries

Operating System:
> Linux 64-bit

Java Release:
> 12

Synopsis:
> Calling java.lang.Class.newInstance from JNI Invocation API causes NullPointerEx

Description:
> 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 Reproduce:
> 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 Result:
> exit 0

Actual Result:
> 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

Source code for an executable test case:
> #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);
> }

Workaround:
> Call via JNI the suggested replacement of clazz.getDeclaredConstructor().newInstance() instead of the deprecated java.lang.Class.newInstance().

Change-Id: I85ff7102a18b98561f188e609873753546bc050d
Reviewed-on: https://gerrit.libreoffice.org/71240
Tested-by: Jenkins
Reviewed-by: 's avatarStephan Bergmann <sbergman@redhat.com>
üst 5dea045b
......@@ -57,8 +57,15 @@ java_lang_Class * java_lang_Class::forName( const OUString& _par0 )
jobject java_lang_Class::newInstanceObject()
{
SDBThreadAttach t;
static jmethodID mID(nullptr);
return callObjectMethod(t.pEnv,"newInstance","()Ljava/lang/Object;", mID);
auto const id = t.pEnv->GetMethodID(static_cast<jclass>(object), "<init>", "()V");
if (id == nullptr) {
ThrowSQLException(t.pEnv, nullptr);
}
auto const obj = t.pEnv->NewObject(static_cast<jclass>(object), id);
if (obj == nullptr) {
ThrowSQLException(t.pEnv, nullptr);
}
return obj;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment