通过JNI NewObject创建实例时,jvm.dll中出现异常0xC0000005



我正在为现有应用程序编写一个插件。实现语言是C。然而,实际功能是用Java实现的。出于这个原因,我使用Java Native Interface(JNI(从C中创建JVM实例。我可以找到合适的Java类并创建一个实例。这就是代码的样子:

login(uintptr_t connection, const char* username, …) {
…
jmethodID constructor = (*env)->GetMethodID(env, ps->class, "<init>", "(JLjava/lang/String;)V");
jstring jusername = (*env)->NewStringUTF(env, username);
jobject instance = (*env)->NewObject(env, ps->class, constructor, connection, jusername);

一切都很好。

在Linux上。

在Windows上,它完全是一团糟。一旦我尝试创建Java类的实例,它就会抛出一个

EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0813751f, pid=8, tid=0x00000009

日志文件中会写入更多详细信息,但堆栈跟踪除了指向jvm.dll中的某个位置之外没有任何帮助。使用调试器进行调试并不是很有见地。请注意,这与这个问题不同。

几天后,我发现了。

我正在调用的构造函数需要一个参数。类型为long(Java(,也称为J(JNI类型签名(,也称jlong(对应的C类型(。Cuintptr_tjlong是兼容的。

在Linux上,我的uintptr_t有8个字节长,因为我在一个有64位应用程序的amd64环境中。对于Windows,该应用程序是在32位中构建的。结果uintptr_t只有4个字节长,但是JVM仍然期望8个字节的jlong。然而,NewObject是一个可变函数,不会自动升级,类型安全性也无法保证。

login(uintptr_t connection, const char* username, …) {
…
jmethodID constructor = (*env)->GetMethodID(env, ps->class, "<init>", "(JLjava/lang/String;)V");
jstring jusername = (*env)->NewStringUTF(env, username);
jlong jconnection = connection;
jobject instance = (*env)->NewObject(env, ps->class, constructor, jconnection, jusername);

解决方案是简单地转换为正确的类型。我预计CallVoidMethod或文档中提到的任何Call*Method也会存在这个陷阱。

相关内容

最新更新