カタカタ

Java で、リフレクション経由でメソッドを呼ぶときにはちゃんと実引数の型チェックが行われるのだが、JNI からだと省略されるみたい。で、やってみたら Throwable じゃないオブジェクトも throw できたり。Mac での例。

$ cat Test.java
public class Test {
    static {
        System.loadLibrary("Test");
    }
    public static void main(String[] args) {
        try {
            throwObject(new Uncatchable());
        } catch (Throwable e) {
            System.out.println("Caught " + e.getMessage());
        }
        System.out.println("Exit");
    }
    static native void throwObject(Object obj);
}
class Uncatchable {
    void hoge1() { System.err.println("<Uncatchable (1)>"); }
    void hoge2() { System.err.println("<Uncatchable (2)>"); }
}
$ cat Test.c
#include <jni.h>
JNIEXPORT void Java_Test_throwObject(JNIEnv *env, jclass cls, jobject obj) {
    if ((*env)->Throw(env, obj)) {
        (*env)->ThrowNew(env, 
                         (*env)->FindClass(env, "java/lang/RuntimeException"), 
                         "Cannot throw it!");
    }
}
$ javac Test.java
$ gcc -dynamiclib -m64 -o libTest.jnilib -I/System/Library/Frameworks/JavaVM.framework/Headers Test.c
$ java Test
Exception in thread "main" <Uncatchable (1)>

しれっと良からぬことになってしまった。(結果は環境によって異なるし、クラッシュする場合もある。)

Linux での実行例。

$ javac Test.java
$ gcc -shared -fPIC -o libTest.so -I/usr/lib/jvm/java-6-sun/include{,/linux} Test.c
$ java -Djava.library.path=. Test
Exception in thread "main" <Uncatchable (2)>