mercredi 18 août 2021

JNI C Reflection puzzle

All code below works as expected, except for the indicated line that crashes. I have spent days scratching my head over this code, checking and re-checking the documentation. I would be delighted if someone could point out the no doubt obvious thing I'm missing.

Main.java:

public class Main {
    public static void main(String[] args) {
        Test tst = new Test();
        System.out.println((String)tst.test());
    }
}

Test.java

public class Test {
    static { System.loadLibrary("test"); }
    public native Object test();
}

test.c

#include <jni.h>
JNIEXPORT jobject JNICALL Java_Test_test(JNIEnv *env, jobject thiz) {
    const char* out = "success";
    do {
        jclass cls_cls = (*env)->FindClass(env, "java/lang/Class");
        if ( !cls_cls ) { out = "FindClass"; break; }
        jmethodID mfn = (*env)->GetStaticMethodID(
            env, cls_cls, "forName", "(Ljava/lang/String;)Ljava/lang/Class;"
        );
        if ( !mfn ) { out = "GetStaticMethodID"; break; }
        // **** lines above succeed, line below segfaults ****
        jclass cls = (jclass) (*env)->CallStaticObjectMethod(
            env, cls_cls, mfn, "java.lang.String"
        );
        if ( (*env)->ExceptionCheck(env) ) { out = "CallStaticObjectMethod"; break; }
    } while ( 0 );
    (*env)->ExceptionClear(env);
    return (jobject) (*env)->NewStringUTF(env, out);
}

compile/exec

gcc -D_REENTRANT -fPIC -Wall -c test.c -o test.o -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux
gcc -D_REENTRANT -fPIC -Wall -shared -o libtest.so -O test.o
javac -Xlint:all Main.java
java -Xcheck:jni -Djava.library.path=. Main

Expected outcome, expressed in pure Java:

Class<?> cls_cls = Class.class;
Method mfn = cls_cls.getDeclaredMethod("forName", String.class);
Class<?> cls = (Class) mfn.invoke(null, "java.lang.String");




Aucun commentaire:

Enregistrer un commentaire