From bfdae9412f6dfbbf961d462debeab392abe447f9 Mon Sep 17 00:00:00 2001 From: Stephan Bergmann Date: Wed, 24 Apr 2019 16:08:06 +0200 Subject: 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 d365f36331874f94bbd9832fbd19ace90fafefec "Allow to pass JAVA_SOURCE/TARGET_VER into configure".) I have entered information about the NullPointerException at , 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 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 . > 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 > > #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(&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: Stephan Bergmann (cherry picked from commit 27c6d1dbdb3dcad02a244ab942adb9222a461e44) Reviewed-on: https://gerrit.libreoffice.org/71347 Reviewed-by: Michael Stahl --- connectivity/source/drivers/jdbc/Class.cxx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'connectivity') diff --git a/connectivity/source/drivers/jdbc/Class.cxx b/connectivity/source/drivers/jdbc/Class.cxx index b41d2f596933..c4dc3f4b5286 100644 --- a/connectivity/source/drivers/jdbc/Class.cxx +++ b/connectivity/source/drivers/jdbc/Class.cxx @@ -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(object), "", "()V"); + if (id == nullptr) { + ThrowSQLException(t.pEnv, nullptr); + } + auto const obj = t.pEnv->NewObject(static_cast(object), id); + if (obj == nullptr) { + ThrowSQLException(t.pEnv, nullptr); + } + return obj; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit