【问题标题】:JNI Getting Exception Info - Attempted to read or write protected memoryJNI 获取异常信息 - 尝试读取或写入受保护的内存
【发布时间】:2012-09-07 21:51:20
【问题描述】:

我正在使用以下代码尝试在 java 中获取一个类 RWException(它扩展了 Exception),以便我可以调用方法“getCode()”来检索错误代码 (int) 并正确处理错误。我浏览了 JNI 文档并创建了以下代码...问题是当我尝试调用无参数方法 getCode() 时遇到 AccessViolation 异常。我得到了类的有效句柄和我正在寻找的方法 id。

jstring o = (jstring)envLoc->CallStaticObjectMethod(cls, mid, jstrUser, jstrPass, jstrGroup);
jthrowable exc = envLoc->ExceptionOccurred();

if (exc) {
    // Get the class
    jclass mvclass = env->GetObjectClass( exc );
    // Get method ID for method
    jmethodID mid = env->GetMethodID(mvclass, "getCode", "()I");
    // Call the method      
    jint code  =  env->CallIntMethod(mvclass, mid);
}

这段代码在使用以下信息在 VS.NET 中调试时给了我一个异常:

试图读取或写入受保护的内存

更新 这是我希望通过上面的 JNI 代码调用的 java 方法:

public int getCode() {
    return code;
}

mvclass 和 mid 对象都已正确实例化,并且应该可以正常工作,除非我遗漏了什么。

更新 2

如果我运行以下代码,则 toString() 方法使用相同的概念:

jstring o = (jstring)envLoc->CallStaticObjectMethod(cls, mid, jstrUser, jstrPass, jstrGroup);
exc = envLoc->ExceptionOccurred();
if (exc) {

    envLoc->ExceptionClear();

    // Get the class
    jclass exccls = envLoc->GetObjectClass(exc);

    // Get method ID for methods 
    jmethodID getCodeMeth = envLoc->GetMethodID(exccls, "getCode", "()I");

    jmethodID getMsgMeth = envLoc->GetMethodID(exccls, "toString", "()Ljava/lang/String;");

    jstring obj = (jstring)envLoc->CallObjectMethod(exccls, getMsgMeth);
    String^ toString = JStringToCliString(obj);

    // this is where the access violation occurs
    jint jcode  =  envLoc->CallIntMethod(exccls, getCodeMeth);
    int code = jcode;
}

所以,toString() 方法返回对象的完整类名,它是正确的 RWException 对象。第一次更新 getCode() 中概述的方法是公开的,等等......所以不知道为什么它会给出内存访问冲突错误。

【问题讨论】:

  • 异常很容易尝试捕获并完成。
  • java 端发生异常...它抛出 RWException 类型的异常,然后我尝试通过 ExceptionOccurred() 方法捕获该异常。然后我需要通过 RWException 对象的代码getCode() 方法 - 在 java 中,它将沿着 int code = oRWexception.getCode(); 的 hte 行
  • 是的,发生异常是因为没有正确捕获
  • @RomanC 通常需要传播异常而不是在内部捕获它。如果每个异常都在抛出它的块内被捕获,那么整个异常点都会丢失。
  • @RomanC 由编写代码的人决定。 OP 正在捕捉异常 - 他的问题正是关于处理它。他只是碰巧用本机方法来做。

标签: java c++ java-native-interface


【解决方案1】:
// exc is the exception object
exc = envLoc->ExceptionOccurred();

...

// exccls is the exception CLASS
jclass exccls = envLoc->GetObjectClass(exc);
jmethodID getCodeMeth = envLoc->GetMethodID(exccls, "getCode", "()I");

...

// CallIntMethod(jobject instance, jmethodID method)
jint jcode = envLoc->CallIntMethod(exccls, getCodeMeth);
// exccls is the CLASS, not the object
// so correct would be:
jint jcode = envLoc->CallIntMethod(exc, getCodeMeth);

哇哦。

而且编译器不会抱怨这一点,因为每个jclass 都是jobject,就像jstring

【讨论】:

  • 和繁荣!你是男人!!!像魅力一样工作。是的,编译器完全没有抱怨。事实上,它给了我方法 ID 和所有东西 - 细节......细节......哈哈。非常感谢我的“主要”男人哈哈
【解决方案2】:

我可以在您的代码中看到的唯一可能的问题是您正在调用一个方法,而异常仍在传播。 envLoc->ExceptionOccurred() 为您提供异常对象,但您仍然必须使用 envLoc->ExceptionClear() 实际捕获它。

【讨论】:

  • 呃...我将方法调用从 getCode 切换到 toString 并且上面的代码工作正常...不知道那意味着什么...
  • 如果为getCodeMeth添加空检查会发生什么?
  • 它通过了,因为它是 not null...所以不确定它为什么会爆炸。确实很奇怪……
  • docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/… 说明了在ExceptionClear 之前可以调用哪些JNI 函数——getMethodID 不在其中。
【解决方案3】:

您在此代码中没有错误检查。您需要检查每个 JNI 操作的结果:GetObjectClass()、GetMethodID()、CallXXXMethod() ... 例如,您假设该类有一个 getCode() 方法,并在不检查的情况下调用它。

【讨论】:

  • 我已经通过 IDE 调试器进行了检查 - GetObjectClass()、GetMethodID() 的所有返回值都是 not null,如原始帖子中所述... CallIntMethod(xxx , xxx) 甚至没有返回 - 它在 JNI.h 调用中因访问冲突异常而崩溃。此外,envLoc 也是有效的。
猜你喜欢
  • 2010-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-05
  • 2014-08-07
相关资源
最近更新 更多