在外部代码执行期间到达JNI异常0xc0000005信号

时间:2018-03-15 06:06:50

标签: java c go java-native-interface cgo

如果我使用CGO运行代码,我目前收到此错误消息。在纯C中使用几乎相同的代码,我没有收到错误消息。

Go(CGO)案例:下面的代码编译时没有错误,但在执行时会发出错误。

package main

/*
#cgo CFLAGS: -Id:/jdk/include -Id:/jdk/include/win32
#cgo LDFLAGS: -Ld:/jdk/jre/bin/server -ljvm

#include <jni.h>

JNIEnv* create_vm(JavaVM **jvm)
{
    JNIEnv* env;
    printf("*env\n");
    JavaVMInitArgs args;
    printf("args\n");
    JavaVMOption options;
    printf("options\n");
    args.version = JNI_VERSION_1_8;
    args.nOptions = 0;
    printf("set values\n");
    int rv;
    rv = JNI_CreateJavaVM(jvm, (void**)&env, &args);
    printf("jni create java vm\n");
    if (rv != JNI_OK) {
        printf("Failed to create Java VMn");
    } else {
        printf("Launched JVM! :)\n");
    }
    return env;
}

void invoke_class(JNIEnv* env)
{
    jclass hello_world_class;
    jmethodID main_method;
    jmethodID square_method;
    jmethodID power_method;
    jint number=20;
    jint exponent=3;
    hello_world_class = (*env)->FindClass(env, "helloWorld");
    main_method = (*env)->GetStaticMethodID(env, hello_world_class, "main", "([Ljava/lang/String;)V");
    square_method = (*env)->GetStaticMethodID(env, hello_world_class, "square", "(I)I");
    power_method = (*env)->GetStaticMethodID(env, hello_world_class, "power", "(II)I");
    (*env)->CallStaticVoidMethod(env, hello_world_class, main_method, NULL);
    printf("%d squared is %d\n", number,
        (*env)->CallStaticIntMethod(env, hello_world_class, square_method, number));
    printf("%d raised to the %d power is %d\n", number, exponent,
        (*env)->CallStaticIntMethod(env, hello_world_class, power_method, number, exponent));
}

void test()
{
    printf("START TEST\n");
    JavaVM *jvm;
    printf("*jvm\n");
    JNIEnv *env;
    printf("*env\n");
    env = create_vm(&jvm);
    printf("create_vm\n");
    invoke_class(env);
    printf("invoke class\n");
}
*/
import "C"

func main() {
    C.test()
}

上面的CGO代码输出

START TEST
*jvm
*env
*env
args
options
set values
Exception 0xc0000005 0x0 0x0 0x50003b6
PC=0x50003b6
signal arrived during external code execution

main._Cfunc_test()
        command-line-arguments/_obj/_cgo_gotypes.go:43 +0x48
main.main()
        D:/Projects/Go/src/loable.tech/go-jasper/main.go:66 +0x27

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
        D:/Go/src/runtime/asm_amd64.s:2197 +0x1
rax     0x6
rbx     0x3100800
rcx     0xcafebabe
rdi     0x1
rsi     0x0
rbp     0x51e052a0
rsp     0x72f678
r8      0x500047b
r9      0x72f840
r10     0x2
r11     0x72f9b0
r12     0x3d8
r13     0x6
r14     0x0
r15     0xf1
rip     0x50003b6
rflags  0x210246
cs      0x33
fs      0x53
gs      0x2b

现在这里是令人困惑的部分。当我使用C代替go并使用与上面几乎相同的代码时,一切都按预期工作。

纯C代码

#include <jni.h>

JNIEnv* create_vm(JavaVM **jvm)
{
    JNIEnv* env;
    printf("*env\n");
    JavaVMInitArgs args;
    printf("args\n");
    JavaVMOption options;
    printf("options\n");
    args.version = JNI_VERSION_1_8;
    args.nOptions = 0;
    printf("set values\n");
    int rv;
    rv = JNI_CreateJavaVM(jvm, (void**)&env, &args);
    printf("jni create java vm\n");
    if (rv != JNI_OK) {
        printf("Failed to create Java VMn");
    } else {
        printf("Launched JVM! :)\n");
    }
    return env;
}

void invoke_class(JNIEnv* env)
{
    jclass hello_world_class;
    jmethodID main_method;
    jmethodID square_method;
    jmethodID power_method;
    jint number=20;
    jint exponent=3;
    hello_world_class = (*env)->FindClass(env, "helloWorld");
    main_method = (*env)->GetStaticMethodID(env, hello_world_class, "main", "([Ljava/lang/String;)V");
    square_method = (*env)->GetStaticMethodID(env, hello_world_class, "square", "(I)I");
    power_method = (*env)->GetStaticMethodID(env, hello_world_class, "power", "(II)I");
    (*env)->CallStaticVoidMethod(env, hello_world_class, main_method, NULL);
    printf("%d squared is %d\n", number,
        (*env)->CallStaticIntMethod(env, hello_world_class, square_method, number));
    printf("%d raised to the %d power is %d\n", number, exponent,
        (*env)->CallStaticIntMethod(env, hello_world_class, power_method, number, exponent));
}

void main()
{
    printf("START TEST\n");
    JavaVM *jvm;
    printf("*jvm\n");
    JNIEnv *env;
    printf("*env\n");
    env = create_vm(&jvm);
    printf("create_vm\n");
    invoke_class(env);
    printf("invoke class\n");
}

这是上面C代码的输出,这是我期待的输出。

START TEST
*jvm
*env
*env
args
options
set values
jni create java vm
Launched JVM! :)
create_vm
Hello, World
20 squared is 400
20 raised to the 3 power is 8000
invoke class

1 个答案:

答案 0 :(得分:0)

不是我常用的机器所以无法验证,但我认为这与JVM启动的工作原理有关。 This answer提供了一些相关信息。我的猜测是golang有一些处理信号/异常的机制,这会干扰JVM信号/异常处理。也许可以通过在golang中显式处理信号来做某事。 signals in golang here有一个入门指南。然而,这只是猜想,因为我现在无法验证它。