David, Thanks for the bug archaeology. Judging by the other commenters, this bug is a regression from jdk5, and has cost many other users hours of frustrating debugging time, so I think an increase to P2 is in order. Since it used to work, it shouldn't be too hard to fix - all you need to do is to properly track registered native methods.
Sorry for not doing this kind of research myself - it's just too painful without my beloved jbugs script :-( Here's an improved version of our test case, with -XX:+PrintJNIResolving output added, that you might add to the bug report. $ cat Test.java; echo ---------------------; cat jvm.cc; echo --------------------------; JDK=`jver 1.7.0-b96`; g++ -I$JDK/include -I$JDK/include/linux -ldl -DJDK=\"$JDK\" 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 <cstdlib> #include <dlfcn.h> #include <jni.h> JavaVM* jvm; JNIEnv* env; const char* libjvm = JDK "/jre/lib/amd64/server/libjvm.so"; const char* loader_url = "file://./"; const char* class_name = "Test"; #define countof(array) (sizeof(array)/sizeof(array[0])) void InitializeJVM() { JavaVMOption options[] = { { (char*)"-Djava.class.path=.", NULL }, { (char*)"-XX:+PrintJNIResolving", NULL }, //{ (char*)"-verbose:jni", NULL }, }; JavaVMInitArgs vm_args; vm_args.version = JNI_VERSION_1_2; vm_args.options = options; vm_args.nOptions = countof(options); vm_args.ignoreUnrecognized = JNI_TRUE; void* handle = dlopen(libjvm, RTLD_LAZY); if (!handle) { fprintf(stderr, "%s\n", dlerror()); exit(1); } 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) { fprintf(stderr, "%s\n", dlerror()); exit(1); } 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); // RegisterNatives must be called after GetMethodID. // If the order is reversed, we get UnsatisfiedLinkError, // which seems like a bug. RegisterNativeMethod(cls); method = env->GetMethodID(cls, "<init>", "()V"); if (env->ExceptionCheck()) env->ExceptionDescribe(); env->NewObject(cls, method); if (env->ExceptionCheck()) env->ExceptionDescribe(); } int main(int argc, char** argv) { InitializeJVM(); Test(); return 0; } -------------------------- [Dynamic-linking native method java.lang.Object.registerNatives ... JNI] [Registering JNI native method java.lang.Object.hashCode] [Registering JNI native method java.lang.Object.wait] [Registering JNI native method java.lang.Object.notify] [Registering JNI native method java.lang.Object.notifyAll] [Registering JNI native method java.lang.Object.clone] [Dynamic-linking native method java.lang.System.registerNatives ... JNI] [Registering JNI native method java.lang.System.currentTimeMillis] [Registering JNI native method java.lang.System.nanoTime] [Registering JNI native method java.lang.System.arraycopy] [Dynamic-linking native method java.lang.Thread.registerNatives ... JNI] [Registering JNI native method java.lang.Thread.start0] [Registering JNI native method java.lang.Thread.stop0] [Registering JNI native method java.lang.Thread.isAlive] [Registering JNI native method java.lang.Thread.suspend0] [Registering JNI native method java.lang.Thread.resume0] [Registering JNI native method java.lang.Thread.setPriority0] [Registering JNI native method java.lang.Thread.yield] [Registering JNI native method java.lang.Thread.sleep] [Registering JNI native method java.lang.Thread.currentThread] [Registering JNI native method java.lang.Thread.countStackFrames] [Registering JNI native method java.lang.Thread.interrupt0] [Registering JNI native method java.lang.Thread.isInterrupted] [Registering JNI native method java.lang.Thread.holdsLock] [Registering JNI native method java.lang.Thread.getThreads] [Registering JNI native method java.lang.Thread.dumpThreads] [Dynamic-linking native method java.security.AccessController.getStackAccessControlContext ... JNI] [Dynamic-linking native method java.security.AccessController.getInheritedAccessControlContext ... JNI] [Dynamic-linking native method java.lang.ClassLoader.registerNatives ... JNI] [Registering JNI native method java.lang.ClassLoader.retrieveDirectives] [Dynamic-linking native method java.security.AccessController.doPrivileged ... JNI] [Dynamic-linking native method java.lang.Class.registerNatives ... JNI] [Registering JNI native method java.lang.Class.getName0] [Registering JNI native method java.lang.Class.getSuperclass] [Registering JNI native method java.lang.Class.getInterfaces] [Registering JNI native method java.lang.Class.getClassLoader0] [Registering JNI native method java.lang.Class.isInterface] [Registering JNI native method java.lang.Class.getSigners] [Registering JNI native method java.lang.Class.setSigners] [Registering JNI native method java.lang.Class.isArray] [Registering JNI native method java.lang.Class.isPrimitive] [Registering JNI native method java.lang.Class.getComponentType] [Registering JNI native method java.lang.Class.getModifiers] [Registering JNI native method java.lang.Class.getDeclaredFields0] [Registering JNI native method java.lang.Class.getDeclaredMethods0] [Registering JNI native method java.lang.Class.getDeclaredConstructors0] [Registering JNI native method java.lang.Class.getProtectionDomain0] [Registering JNI native method java.lang.Class.setProtectionDomain0] [Registering JNI native method java.lang.Class.getDeclaredClasses0] [Registering JNI native method java.lang.Class.getDeclaringClass] [Registering JNI native method java.lang.Class.getGenericSignature] [Registering JNI native method java.lang.Class.getRawAnnotations] [Registering JNI native method java.lang.Class.getConstantPool] [Registering JNI native method java.lang.Class.desiredAssertionStatus0] [Registering JNI native method java.lang.Class.getEnclosingMethod0] [Dynamic-linking native method java.lang.Class.getPrimitiveClass ... JNI] [Dynamic-linking native method java.lang.System.initProperties ... JNI] [Dynamic-linking native method sun.misc.Unsafe.registerNatives ... JNI] [Registering JNI native method sun.misc.Unsafe.getLoadAverage] [Dynamic-linking native method java.lang.Throwable.fillInStackTrace ... JNI] [Registering JNI native method sun.misc.Unsafe.copyMemory] [Registering JNI native method sun.misc.Unsafe.setMemory] [Registering JNI native method sun.misc.Unsafe.getObject] [Registering JNI native method sun.misc.Unsafe.putObject] [Registering JNI native method sun.misc.Unsafe.getObjectVolatile] [Registering JNI native method sun.misc.Unsafe.putObjectVolatile] [Registering JNI native method sun.misc.Unsafe.getBoolean] [Registering JNI native method sun.misc.Unsafe.putBoolean] [Registering JNI native method sun.misc.Unsafe.getBooleanVolatile] [Registering JNI native method sun.misc.Unsafe.putBooleanVolatile] [Registering JNI native method sun.misc.Unsafe.getByte] [Registering JNI native method sun.misc.Unsafe.putByte] [Registering JNI native method sun.misc.Unsafe.getByteVolatile] [Registering JNI native method sun.misc.Unsafe.putByteVolatile] [Registering JNI native method sun.misc.Unsafe.getShort] [Registering JNI native method sun.misc.Unsafe.putShort] [Registering JNI native method sun.misc.Unsafe.getShortVolatile] [Registering JNI native method sun.misc.Unsafe.putShortVolatile] [Registering JNI native method sun.misc.Unsafe.getChar] [Registering JNI native method sun.misc.Unsafe.putChar] [Registering JNI native method sun.misc.Unsafe.getCharVolatile] [Registering JNI native method sun.misc.Unsafe.putCharVolatile] [Registering JNI native method sun.misc.Unsafe.getInt] [Registering JNI native method sun.misc.Unsafe.putInt] [Registering JNI native method sun.misc.Unsafe.getIntVolatile] [Registering JNI native method sun.misc.Unsafe.putIntVolatile] [Registering JNI native method sun.misc.Unsafe.getLong] [Registering JNI native method sun.misc.Unsafe.putLong] [Registering JNI native method sun.misc.Unsafe.getLongVolatile] [Registering JNI native method sun.misc.Unsafe.putLongVolatile] [Registering JNI native method sun.misc.Unsafe.getFloat] [Registering JNI native method sun.misc.Unsafe.putFloat] [Registering JNI native method sun.misc.Unsafe.getFloatVolatile] [Registering JNI native method sun.misc.Unsafe.putFloatVolatile] [Registering JNI native method sun.misc.Unsafe.getDouble] [Registering JNI native method sun.misc.Unsafe.putDouble] [Registering JNI native method sun.misc.Unsafe.getDoubleVolatile] [Registering JNI native method sun.misc.Unsafe.putDoubleVolatile] [Registering JNI native method sun.misc.Unsafe.getByte] [Registering JNI native method sun.misc.Unsafe.putByte] [Registering JNI native method sun.misc.Unsafe.getShort] [Registering JNI native method sun.misc.Unsafe.putShort] [Registering JNI native method sun.misc.Unsafe.getChar] [Registering JNI native method sun.misc.Unsafe.putChar] [Registering JNI native method sun.misc.Unsafe.getInt] [Registering JNI native method sun.misc.Unsafe.putInt] [Registering JNI native method sun.misc.Unsafe.getLong] [Registering JNI native method sun.misc.Unsafe.putLong] [Registering JNI native method sun.misc.Unsafe.getFloat] [Registering JNI native method sun.misc.Unsafe.putFloat] [Registering JNI native method sun.misc.Unsafe.getDouble] [Registering JNI native method sun.misc.Unsafe.putDouble] [Registering JNI native method sun.misc.Unsafe.getAddress] [Registering JNI native method sun.misc.Unsafe.putAddress] [Registering JNI native method sun.misc.Unsafe.allocateMemory] [Registering JNI native method sun.misc.Unsafe.reallocateMemory] [Registering JNI native method sun.misc.Unsafe.freeMemory] [Registering JNI native method sun.misc.Unsafe.objectFieldOffset] [Registering JNI native method sun.misc.Unsafe.staticFieldOffset] [Registering JNI native method sun.misc.Unsafe.staticFieldBase] [Registering JNI native method sun.misc.Unsafe.ensureClassInitialized] [Registering JNI native method sun.misc.Unsafe.arrayBaseOffset] [Registering JNI native method sun.misc.Unsafe.arrayIndexScale] [Registering JNI native method sun.misc.Unsafe.addressSize] [Registering JNI native method sun.misc.Unsafe.pageSize] [Registering JNI native method sun.misc.Unsafe.defineClass] [Registering JNI native method sun.misc.Unsafe.defineClass] [Registering JNI native method sun.misc.Unsafe.allocateInstance] [Registering JNI native method sun.misc.Unsafe.monitorEnter] [Registering JNI native method sun.misc.Unsafe.monitorExit] [Registering JNI native method sun.misc.Unsafe.tryMonitorEnter] [Registering JNI native method sun.misc.Unsafe.throwException] [Registering JNI native method sun.misc.Unsafe.compareAndSwapObject] [Registering JNI native method sun.misc.Unsafe.compareAndSwapInt] [Registering JNI native method sun.misc.Unsafe.compareAndSwapLong] [Registering JNI native method sun.misc.Unsafe.putOrderedObject] [Registering JNI native method sun.misc.Unsafe.putOrderedInt] [Registering JNI native method sun.misc.Unsafe.putOrderedLong] [Registering JNI native method sun.misc.Unsafe.park] [Registering JNI native method sun.misc.Unsafe.unpark] [Dynamic-linking native method java.lang.Float.floatToRawIntBits ... JNI] [Dynamic-linking native method java.lang.Double.doubleToRawLongBits ... JNI] [Dynamic-linking native method sun.reflect.Reflection.getCallerClass ... JNI] [Dynamic-linking native method java.lang.String.intern ... JNI] [Dynamic-linking native method java.lang.Object.getClass ... JNI] [Dynamic-linking native method java.lang.Class.forName0 ... JNI] [Dynamic-linking native method sun.reflect.Reflection.getClassAccessFlags ... JNI] [Dynamic-linking native method sun.reflect.NativeConstructorAccessorImpl.newInstance0 ... JNI] [Dynamic-linking native method sun.misc.VM.initialize ... JNI] [Dynamic-linking native method java.io.FileSystem.getFileSystem ... JNI] [Dynamic-linking native method java.io.UnixFileSystem.initIDs ... JNI] [Dynamic-linking native method java.lang.System.mapLibraryName ... JNI] [Dynamic-linking native method java.io.UnixFileSystem.getBooleanAttributes0 ... JNI] [Dynamic-linking native method java.io.UnixFileSystem.canonicalize0 ... JNI] [Dynamic-linking native method java.lang.ClassLoader$NativeLibrary.load ... JNI] [Dynamic-linking native method java.io.FileInputStream.initIDs ... JNI] [Dynamic-linking native method java.io.FileDescriptor.initIDs ... JNI] [Dynamic-linking native method java.io.FileOutputStream.initIDs ... JNI] [Dynamic-linking native method java.lang.System.setIn0 ... JNI] [Dynamic-linking native method java.lang.System.setOut0 ... JNI] [Dynamic-linking native method java.lang.System.setErr0 ... JNI] [Dynamic-linking native method sun.misc.Signal.findSignal ... JNI] [Dynamic-linking native method sun.misc.Signal.handle0 ... JNI] [Dynamic-linking native method java.lang.Runtime.maxMemory ... JNI] [Dynamic-linking native method java.lang.Compiler.registerNatives ... JNI] [Registering JNI native method java.lang.Compiler.compileClass] [Registering JNI native method java.lang.Compiler.compileClasses] [Registering JNI native method java.lang.Compiler.command] [Registering JNI native method java.lang.Compiler.enable] [Registering JNI native method java.lang.Compiler.disable] [Dynamic-linking native method java.lang.ClassLoader.getCaller ... JNI] [Dynamic-linking native method java.lang.ClassLoader$NativeLibrary.find ... JNI] [Dynamic-linking native method java.security.AccessController.doPrivileged ... JNI] [Dynamic-linking native method java.io.FileInputStream.open ... JNI] [Dynamic-linking native method java.io.FileInputStream.readBytes ... JNI] [Dynamic-linking native method java.io.FileInputStream.available ... JNI] [Dynamic-linking native method java.lang.reflect.Array.newArray ... JNI] [Dynamic-linking native method java.io.FileInputStream.close0 ... JNI] [Dynamic-linking native method java.io.UnixFileSystem.list ... JNI] [Dynamic-linking native method java.lang.ClassLoader.findLoadedClass0 ... JNI] [Dynamic-linking native method java.lang.ClassLoader.findBootstrapClass ... JNI] [Dynamic-linking native method java.security.AccessController.doPrivileged ... JNI] [Dynamic-linking native method java.io.UnixFileSystem.getLength ... JNI] [Dynamic-linking native method sun.misc.Perf.registerNatives ... JNI] [Registering JNI native method sun.misc.Perf.attach] [Registering JNI native method sun.misc.Perf.detach] [Registering JNI native method sun.misc.Perf.createLong] [Registering JNI native method sun.misc.Perf.createByteArray] [Registering JNI native method sun.misc.Perf.highResCounter] [Registering JNI native method sun.misc.Perf.highResFrequency] [Dynamic-linking native method java.lang.ClassLoader.defineClass1 ... JNI] [Dynamic-linking native method java.lang.ClassLoader.resolveClass0 ... JNI] [Registering JNI native method Test.testNative] [Dynamic-linking native method java.io.FileOutputStream.writeBytes ... JNI] My class loader is sun.misc.launcher$appclassloa...@b92d342 Exception in thread "main" java.lang.UnsatisfiedLinkError: Test.testNative()V [Dynamic-linking native method java.lang.Throwable.getStackTraceDepth ... JNI] [Dynamic-linking native method java.lang.Throwable.getStackTraceElement ... JNI] at Test.testNative(Native Method) at Test.<init>(Test.java:4) Martin On Wed, Jun 9, 2010 at 03:25, David Holmes <david.hol...@oracle.com> wrote: > 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$appclassloa...@1f7182c1 >> Successfully called registered native method >> back to Java >> >> Thanks, >> >> Martin >