Must call RegisterNatives after getMethodID, else get UnsatisfiedLinkError

David Holmes David.Holmes at oracle.com
Wed Jun 9 03:25:06 PDT 2010


Hi Martin,

Turns out this is a known (and old) issue (thanks Yuri!):

CR 6493522 "JNI_RegisterNatives fails to bind a method of an 
uninitialized class"

I'll add this email info to the CR.

David

Martin Buchholz said the following on 06/09/10 09:12:
> Hi ClassLoader maintainers,
> 
> This is a bug report.
> 
> (I think this is a hotspot bug, but it might be a core library
> ClassLoader bug or even a URLClassLoader bug)
> 
> If you use RegisterNatives with a class loaded using URLClassLoader,
> you must call GetMethodID
> before RegisterNatives, or you get an UnsatisfiedLinkError as in the
> test case below
> 
> (you will need to edit the below to fill in the location of your jni
> include directory and your libjvm.so)
> 
> $ cat Test.java; echo ---------------------; cat jvm.cc; echo
> --------------------------; g++ -I$JDK/include -I$JDK/include/linux
> -ldl jvm.cc && ./a.out
> public class Test {
>   public Test() {
>     System.out.println("My class loader is " + getClass().getClassLoader());
>     testNative();
>     System.out.println("back to Java");
>   }
>   public static native void testNative();
> }
> ---------------------
> #include <cstdio>
> #include <dlfcn.h>
> #include <jni.h>
> 
> JavaVM* jvm;
> JNIEnv* env;
> const char* libjvm =
>     "$JDKDIR/libjvm.so";
> const char* loader_url = "file://./";
> const char* class_name = "Test";
> 
> void InitializeJVM() {
>   JavaVMOption options[1];
>   options[0].optionString = (char*)"-Djava.class.path=.";
>   //options[1].optionString = (char*)"-verbose:jni";
> 
>   JavaVMInitArgs vm_args;
>   vm_args.version = JNI_VERSION_1_2;
>   vm_args.options = options;
>   vm_args.nOptions = 2;
>   vm_args.ignoreUnrecognized = JNI_TRUE;
> 
>   void* handle = dlopen(libjvm, RTLD_LAZY);
>   if (handle == NULL) perror("dlopen");
>   jint JNICALL (*func_create_java_vm)(JavaVM**, void**, void*) =
>       reinterpret_cast<jint JNICALL (*)(JavaVM**, void**, void*)>
>       (dlsym(handle, "JNI_CreateJavaVM"));
>   if (func_create_java_vm == NULL) perror("dlsym");
>   jint result = (*func_create_java_vm)(&jvm, (void**)(&env), &vm_args);
> }
> 
> void TestNative(JNIEnv* env, jclass cls) {
>   printf("Successfully called registered native method\n");
> }
> 
> void RegisterNativeMethod(jclass cls) {
>   static const JNINativeMethod jni_method =
>       { (char*)"testNative",
>         (char*)"()V",
>         (void*)&TestNative };
>   env->RegisterNatives(cls, &jni_method, 1);
>   if (env->ExceptionCheck()) env->ExceptionDescribe();
> }
> 
> void Test() {
>   // URL[] urls = {new URL(url)}
>   jclass cls = env->FindClass("java/net/URL");
>   jmethodID method = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;)V");
>   jstring jurl_str = env->NewStringUTF(loader_url);
>   jobject jurl = env->NewObject(cls, method, jurl_str);
>   jobjectArray jurls = env->NewObjectArray(1, cls, jurl);
> 
>   // URLClassLoader loader = new URLClassLoaer(urls)
>   cls = env->FindClass("java/net/URLClassLoader");
>   method = env->GetMethodID(cls, "<init>", "([Ljava/net/URL;)V");
>   jobject jloader = env->NewObject(cls, method, jurls);
> 
>   // Class cls = loader.loadClass(name)
>   method = env->GetMethodID(
>       cls, "loadClass", "(Ljava/lang/String;Z)Ljava/lang/Class;");
>   jstring jname = env->NewStringUTF(class_name);
>   cls = (jclass)env->CallObjectMethod(jloader, method, jname, (jboolean) true);
> 
>   method = env->GetMethodID(cls, "<init>", "()V");
>   if (env->ExceptionCheck()) env->ExceptionDescribe();
> 
>   // RegisterNatives must be called after GetMethodID.
>   // If the order is reversed, we get UnsatisfiedLinkError,
>   // which seems like a bug.
>   RegisterNativeMethod(cls);
> 
>   env->NewObject(cls, method);
>   if (env->ExceptionCheck()) env->ExceptionDescribe();
> }
> 
> int main(int argc, char** argv) {
>   InitializeJVM();
>   Test();
> 
>   return 0;
> }
> --------------------------
> My class loader is sun.misc.Launcher$AppClassLoader at 1f7182c1
> Successfully called registered native method
> back to Java
> 
> Thanks,
> 
> Martin


More information about the hotspot-runtime-dev mailing list