I am currently getting this error message if I run the code using CGO. Using almost the same code in pure C, I don't get the error message.
Go (CGO) case: The code below will compile without errors but will give out an error when executed.
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()
}
Output of the CGO code above
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
Now here's the confusing part. When I use C instead of go and using almost the same code as above, everything works as expected.
Pure C code
#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");
}
This is the output of the C code above, which is the output that I am expecting.
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
Not at my usual machine so can't verify, but I think this has something to do with how the JVM startup works. This answer provides some info on that. My guess is that golang has some mechanism for processing signals/exceptions and that that interferes with the JVMs signal/exception handling. Maybe it is possible to do something by explicitly handling signals in golang. There is a starting guide for signals in golang here. Again this is just conjecture though, since I can't verify it at the moment.
User contributions licensed under CC BY-SA 3.0