【问题标题】:What does a Java method return to a JNI caller when it throws an exception?当 Java 方法抛出异常时,它会向 JNI 调用者返回什么?
【发布时间】:2013-10-01 15:42:52
【问题描述】:

假设我有以下 Java 代码:

public class Test {
  public static int foo() {
    throw new RuntimeException();
  }
}

它以通常的方式加载本机库。本机库注册并缓存 JVM 或其他任何东西,然后稍后执行此函数:

JNIEnv* sEnv; // initialised somewhere properly
void throwMeARiver() {
  jclass c = sEnv->FindClass("Test");
  jmethodID m = sEnv->GetStaticMethodID(c, "foo", "()I");
  jint i = sEnv->CallStaticIntMethod(c, m);
  printf("Got %d\n", (int)i);
}

显然 sEnv->CheckException() 现在将返回 JNI_TRUE,但是本机函数会打印出什么?在 Java 中,抛出异常会使 JVM 停止执行它所在的方法,直到找到合适的处理程序,所以 foo() 的返回值是未定义的。那么我也是未定义的吗?

我找不到任何规格或其他说明,所以大概我 /is/ 未定义。在这种情况下,与大多数 JNI 函数不同,CallStaticIntMethod 没有“正常”范围。

我现在正在尝试这个,但我主要是问这个,看看某处是否有强制行为。

【问题讨论】:

    标签: java exception java-native-interface


    【解决方案1】:

    虽然变量 i 将被定义,但它的值是未确定的。在这种情况下,该值很可能为 0,但前提是 JVM 在其实现中初始化了该值。否则,它将等于内存中存在的任何数据。

    由本机函数的实现者通过env->CheckException()env->ExceptionOccurred()env->ExceptionDescribe() 正确检查CallXXXMethod() 之后的异常。最后,调用env->ClearException() 来移除异常。

    【讨论】:

    • 根据我在 Android 上的测试,返回的值是发生在某个不可预测的内存位置中的任何值。
    【解决方案2】:

    不,JNI CheckException() 不等同于 Java try ... catch,因此您的新 RuntimeException() 将进一步传播,可能根本不会被捕获。

    感谢@EJP 纠正我:实际上,来自Java 的任何Throwable 都会被C/C++ 调用者拦截。根据我在 Android 上的测试,返回的值是发生在某个不可预测的内存位置(堆栈?)中的任何值。

    有关 JNI 和异常的更多讨论,请参阅How to catch JNI/Java Exception

    【讨论】:

    • 他没有问是否等同于Javatry.他问返回value是什么,你没有回答他。您的回答暗示 CheckException() 不会为不正确的 RuntimeException, 返回 true。
    • @EJP 那应该是“她”/“她”。
    • @EJP:谢谢,我错了:实际上,任何来自 Java 的 Throwable 都会被 C/C++ 调用者拦截。每天我都会学到一些新东西。
    猜你喜欢
    • 1970-01-01
    • 2011-05-07
    • 2013-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多