JNI_CreateJavaVM上的Segfault 我试图第一次通过JNI从C++加载JVM,但我似乎无法使它工作。当我调用JNI_CreateJavaVM时,我得到一个segfault

JNI_CreateJavaVM上的Segfault 我试图第一次通过JNI从C++加载JVM,但我似乎无法使它工作。当我调用JNI_CreateJavaVM时,我得到一个segfault,c++,linux,java-native-interface,shared-libraries,C++,Linux,Java Native Interface,Shared Libraries,代码非常直截了当(主要从在线示例中复制): 当我在gdb中运行它时,我会得到前三条打印语句,然后是: Program received signal SIGSEGV, Segmentation fault 0x0000003249479e27 in strncmp () from /lib64/libc.so.6 (gdb) bt #0 0x0000003249479e27 in strncmp () from /lib64/libc.so.6 #1 0x00002aaaaacd8c10 in

代码非常直截了当(主要从在线示例中复制):

当我在gdb中运行它时,我会得到前三条打印语句,然后是:

Program received signal SIGSEGV, Segmentation fault
0x0000003249479e27 in strncmp () from /lib64/libc.so.6
(gdb) bt
#0 0x0000003249479e27 in strncmp () from /lib64/libc.so.6
#1 0x00002aaaaacd8c10 in Arguments::process_sun_java_launcher_properties(JavaVMInitArgs*) () from /usr/java/jdk1.6.0_45/jre/lib/amd64/server/libjvm.so
#2 0x00002aaaab2cfe7d in Thread::create_vm(JavaVMInitArgs*, bool*) () from /usr/java/jdk1.6.0_45/jre/lib/amd64/server/libjvm.so
#3 0x00002aaaaafcc800 in JNI_CreateJavaVM () from /usr/java/jdk1.6.0_45/jre/lib/amd64/server/libjvm.so
#4 0x0000000000400761 in main(argc=1, argv=0x7fffffffe568) at src/jni/ExpCppPart.cpp:22
我的猜测是,问题更多地与如何设置环境或如何构建可执行文件有关,而不是与代码有关。我已经有几年没有真正处理过链接共享库的问题了,所以我很可能把事情搞砸了

你知道我做错了什么吗

更新 我尝试使用dlopen加载库(因为我在一些使用JNI的Linux代码中看到了它)。这没什么区别,但我想我会把它放在这里,看看它是否能给任何人一个暗示,说明我可能做错了什么

再一次,我是从一个没有连接到互联网的系统中手工复制的,所以可能会有一些打字错误

#include<stdio.h>
#include<jni.h>
#include<dlfcn.h>

using namespace std;

//Create type for pointer to the JNI_CreateJavaVM function
typedef jint (*CreateJvmFuncPtr) (JavaVM**, void**, JavaVMInitArgs*);

//New method returns pointer to the JNI_CreateJavaVM function
CreateJvmFuncPtr findCreateJvm() {
    CreateJavaFuncPtr createJvm = NULL;

    void* jvmLib = dlopen("libjvm.so", RTLD_LAZY); //Get handle to jvm shared library
    char* error = dlerror(); //Check for errors on dlopen

    if(jvmLib = NULL || error != NULL) {
        printf("FailedToLoadJVM\n");
    }

    //Load pointer to the function within the shared library
    createJvm = (CreateJvmFuncPtr) dlsym(jvmLib, "JNI_CreateJavaVM");

    error = dlerror();
    if(error != NULL) {
        printf("Success\n");
    }

    return createJVM;
}

int main(int argc, char** argv) {

    printf("Initializing JVM\n");
    JavaVM *jvm;
    JNIEnv *env;

    printf("Setting up args\n";
    JavaVMInitArgs vm_args;
    JavaVMOption* options = new JavaVMOption[1];
    options[0].optionString = "-Djava.class.path=.";
    vm_args.version = JNI_VERSION_1_6;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = false;

    printf("Attempting to create JVM\n");
    //Old code: jint rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    //New code:
    CreateJvmFuncPtr createJVM = findCreateJvm();
    printf("findCreateJVM() returned 0x%x\n", createJVM);

    jint rc = createJVM(&jvm, (void**)&env, &vm_args);
    //End new code

    if(rc != JNI_OK) {
        printf("didn't work :(\n");
    }
    else {
        printf("JVM load succeeded!\n");
        jint ver = env->GetVersion();
        printf("Version: %i.%i\n", (ver>>16)&0x0f, ver&0x0f);

        printf("Cleaning up\n");
        delete options;
        jvm->DestroyJavaVM();
    }
    printf("Done\n");
}

因此,看起来程序至少可以找到库/函数。但当它被调用时,会出现问题。对我来说,这表明它可能只是一个简单的API误解(我传递的不是我应该传递的东西),或者共享库中有一些奇怪的东西。如果共享库的编译架构/字号与我的程序的编译架构/字号不同,可能会导致这种情况吗?如果是这样,我如何检查我的程序和库的目标体系结构?

您得到的错误在这一行:

jint rc = JNI_CreateJavaVM(&jvm, (void**)&&env, &vm_args);
您正在请求指向env的指针的地址;然而,如果您查看参考资料:


这太尴尬了

我终于发现了我的问题,堆栈溢出问题上的任何人都无法修复它,因为我在问题中发布的代码实际上是正确的,但它与我运行的代码不同

正如我所提到的,我在一个没有互联网接入的独立系统上运行这段代码,所以我不得不手工复制代码。临摹时,我改正了错误

我的独立系统上的代码包括以下几行:

JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = "-Djava.class.path=.";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.ignoreUnrecognized = false;
你会注意到这和我在问题中发布的代码不一样。因为它缺少行:

vm_args.options = options;

因此,它当然会导致segfault,因为vm_args.options从未设置为任何值。

对于segfault,我感觉您使用的代码存在逻辑错误。因为segfault试图访问不在那里的内存,比如当您越过数组的边界时。同样有意义的是,您可以获得前三个打印语句,因为在
jint rc=JNI_CreateJavaVM(&jvm,(void**)和&env,&vm_args)行失败您使用什么命令来运行程序?也可以使用-Wall和-WerrorI编译,我只使用./exe/jniExp或gdb运行,gdb exe/jniExp后跟run。在这种情况下,我认为它可能试图读取不存在的预期参数。我的意思是没有注释很难阅读,所以我可能会错。下面是我看到的带有更多注释的示例代码:哦,这实际上是一个打字错误。我正在开发的机器不能上网,所以我不得不手工复制代码,结果把事情搞砸了。在我实际运行这个的机器上,它只有一个“&”。我会在我的帖子里修改的。根据我发布的内容,你是绝对正确的。如果这只是一个打字错误,那么代码应该可以正常工作。它在mac或linux上都没有失败,但都运行最新的Java8。嗯。。。好吧,我的猜测是,如果它在Java8上工作,那么它在Java6上也会工作(因为我复制的示例是为Java6制作的)。我想这一定是因为我的环境是如何建立的。非常感谢您查看它。我刚刚在Java6上测试了它-看起来和您的系统上的一样,并且工作正常。我唯一的怀疑是行
options[0].optionString=“-Djava.class.path=”
实际上不是您在
.cpp
文件中得到的。有一个
strlen()
可以捕获空指针,但是如果您使用单引号,故意将其转换为char*,并忽略警告,我可能会触发与您相同的错误。这是一个好主意,但不幸的是我使用了双引号,所以不是这样。
jint rc = JNI_CreateJavaVM(&jvm, (void**)&&env, &vm_args);
#include <jni.h>       /* where everything is defined */
...
JavaVM *jvm;       /* denotes a Java VM */
JNIEnv *env;       //<!-- same as yours
JavaVMInitArgs vm_args; /* JDK/JRE 6 VM initialization arguments */
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = "-Djava.class.path=/usr/lib/java";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.options = options;
vm_args.ignoreUnrecognized = false;
/* load and initialize a Java VM, return a JNI interface
 * pointer in env */
JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); // <!-- NOT the same!
delete options;
/* invoke the Main.test method using the JNI */
jclass cls = env->FindClass("Main");
jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V");
env->CallStaticVoidMethod(cls, mid, 100);
/* We are done. */
jvm->DestroyJavaVM();
jint rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
JavaVMOption* options = new JavaVMOption[1];
options[0].optionString = "-Djava.class.path=.";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 1;
vm_args.ignoreUnrecognized = false;
vm_args.options = options;