C + JNI 无法执行非常简单的程序



我将从我的代码开始:

#include <jni.h>
int main(int argc, char const *argv[]) {
JavaVMInitArgs args;
JNIEnv *env;
JavaVM *vm;
args.version = JNI_VERSION_1_8;
args.ignoreUnrecognized = JNI_FALSE;
JNI_CreateJavaVM(&vm, (void **)&env, &args);
jclass System;
jclass PrintStream;
jobject out;
jfieldID outID;
jstring someText;
jmethodID println;
someText = (*env)->NewStringUTF(env, "Hello World");
System = (*env)->FindClass(env, "java/lang/System");
PrintStream = (*env)->FindClass(env, "java/io/PrintStream");
outID = (*env)->GetStaticFieldID(env, System, "out", "Ljava/io/PrintStream;");
out = (*env)->GetStaticObjectField(env, System, outID);
println = (*env)->GetMethodID(env, PrintStream, "println", "(Ljava/lang/String;)V");
(*env)->CallVoidMethod(env, out, println, someText);
return 0;
}

我希望它打印"Hello World",但它没有,相反Segmentation fault (core dumped)我得到一个烦人的错误。我无法弄清楚这段代码有什么问题,我试图在someText = (*env)->NewStringUTF(env, "Hello World");后注释掉所有内容,程序没有崩溃,我也试图只注释someText = (*env)->NewStringUTF(env, "Hello World");,我也工作了。我什至将println签名更改为"boolean"并将 0 传递给它,程序打印"false",正如我所期望的那样,所以我想这是NewStringUTF方法的错误。

openjdk version "1.8.0_131" OpenJDK Runtime Environment (build 1.8.0_131-b11) OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)

(gdb) bt
#0  0x00007ffff713b2ff in ?? () from /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/libjvm.so
#1  0x00007ffff78955c4 in ?? () from /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/libjvm.so
#2  0x00007ffff7507e71 in JNI_CreateJavaVM () from /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/libjvm.so
#3  0x0000000000400558 in main (argc=1, argv=0x7fffffffe678) at main.c:11

(gdb) info f
Stack level 0, frame at 0x7fffffffe310:
rip = 0x7ffff713b2ff; saved rip = 0x7ffff78955c4
called by frame at 0x7fffffffe490
Arglist at 0x7fffffffe2c8, args: 
Locals at 0x7fffffffe2c8, Previous frame's sp is 0x7fffffffe310
Saved registers:
rbx at 0x7fffffffe2d8, rbp at 0x7fffffffe300, r12 at 0x7fffffffe2e0, r13 at 0x7fffffffe2e8, r14 at 0x7fffffffe2f0,
r15 at 0x7fffffffe2f8, rip at 0x7fffffffe308

注释掉NewStringUTF

(gdb) bt
#0  0x00007fffe61082b4 in ?? ()
#1  0x0000000000000246 in ?? ()
#2  0x00007fffe6108160 in ?? ()
#3  0x00007fffffffe0f0 in ?? ()
#4  0x00007fffffffe090 in ?? ()
#5  0x00007ffff78f6748 in ?? () from /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/libjvm.so
Backtrace stopped: previous frame inner to this frame (corrupt stack?)
(gdb) info f
Stack level 0, frame at 0x7fffffffde80:
rip = 0x7fffe61082b4; saved rip = 0x246
called by frame at 0x7fffffffde88
Arglist at 0x7fffffffde70, args: 
Locals at 0x7fffffffde70, Previous frame's sp is 0x7fffffffde80
Saved registers:
rip at 0x7fffffffde78

经过一些观察,看起来JNI_CreateJavaVM函数在添加NewStringUTF后崩溃,但在删除后它正在"工作"。这有多奇怪?

这是我正在使用的JDK和JRE:https://www.archlinux.org/packages/extra/x86_64/jdk8-openjdk/

我正在使用以下命令进行编译:

gcc 
-I /usr/lib/jvm/java-8-openjdk/include/ 
-I /usr/lib/jvm/java-8-openjdk/include/linux/ 
-L /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/ 
-l jvm 
main.c

并运行文件

export LD_LIBRARY_PATH=/usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/
./a.out

不同的代码,相同的问题:

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[]) {
JavaVMInitArgs args;
JavaVM *jvm;
JNIEnv *env;
args.version = JNI_VERSION_1_8;
args.ignoreUnrecognized = JNI_FALSE;
printf("%sn", "Creating VM");
JNI_CreateJavaVM(&jvm, (void **)&env, &args);
printf("%sn", "VM Was Created");
jclass String = (*env)->FindClass(env, "java/lang/String");
if (String == NULL) {
printf("%sn", "String was NULL");
exit(1);
}
jmethodID method = (*env)->GetMethodID(env, String, "codePointAt", "(I)I");
if (method == NULL) {
printf("%sn", "method was NULL");
exit(1);
}
printf("%sn", "I am finishing here");
(*jvm)->DestroyJavaVM(jvm);
return 0;
}

编译并运行:

$ gcc 
> -I /usr/lib/jvm/java-8-openjdk/include/ 
> -I /usr/lib/jvm/java-8-openjdk/include/linux/ 
> -L /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/ 
> -l jvm 
> main.c && ./a.out
Creating VM
Segmentation fault (core dumped)

但是如果我注释代码的一部分:

#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char const *argv[]) {
JavaVMInitArgs args;
JavaVM *jvm;
JNIEnv *env;
args.version = JNI_VERSION_1_8;
args.ignoreUnrecognized = JNI_FALSE;
printf("%sn", "Creating VM");
JNI_CreateJavaVM(&jvm, (void **)&env, &args);
printf("%sn", "VM Was Created");
jclass String = (*env)->FindClass(env, "java/lang/String");
if (String == NULL) {
printf("%sn", "String was NULL");
exit(1);
}
/*jmethodID method = (*env)->GetMethodID(env, String, "codePointAt", "(I)I");
if (method == NULL) {
printf("%sn", "method was NULL");
exit(1);
}*/
printf("%sn", "I am finishing here");
(*jvm)->DestroyJavaVM(jvm);
return 0;
}

编译并运行:

$ gcc 
> -I /usr/lib/jvm/java-8-openjdk/include/ 
> -I /usr/lib/jvm/java-8-openjdk/include/linux/ 
> -L /usr/lib/jvm/java-8-openjdk/jre/lib/amd64/server/ 
> -l jvm 
> main.c && ./a.out
Creating VM
VM Was Created
I am finishing here

所以,对我来说,它按预期工作:

> gdb ./main
...
(gdb) run
Starting program: ..../issue/main
[New Thread 0x1403 of process 2600]
[New Thread 0x1503 of process 2600]
warning: unhandled dyld version (15)
Hello World
[Inferior 1 (process 2600) exited normally]
(gdb)

但是,我的环境略有不同。 macOS,我使用Oracle的JDK。

也许您可以尝试安装调试信息并检查JDK内部到底发生了什么?

最新更新