为什么此JNI仅在Windows上调用segfault? [英] Why does this JNI call segfault on Windows only?

查看:61
本文介绍了为什么此JNI仅在Windows上调用segfault?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些使用JNI将字符串添加到Java数组的C代码.对NewStringUTF segfaults的调用-但仅在32位Windows 7上(在VirtualBox VM中,这是我必须测试的全部).在某些情况下,它会先调用SetObjectArrayElement然后进行段错误.

I have some C code that adds strings to a Java array using JNI. The call to NewStringUTF segfaults -- but only on Windows 7 32-bit (in a VirtualBox VM, which is all I have to test on). In some cases, it makes it to SetObjectArrayElement call and then segfaults.

void launch_jvm_in_proc(mrb_state *mrb, CreateJavaVM_t *createJavaVM, const char *java_main_class, const char **java_opts, int java_optsc, const char **v, int prgm_optsc) {
  int i;
  JavaVM *jvm;
  JNIEnv *env;
  //...
  jclass j_class_string = (*env)->FindClass(env, "java/lang/String");
  jstring j_string_arg = (*env)->NewStringUTF(env, "");
  jobjectArray main_args = (*env)->NewObjectArray(env, prgm_optsc, j_class_string, j_string_arg);

  for (i = 0; i < prgm_optsc; i++) {
    j_string_arg = (*env)->NewStringUTF(env, (char *) prgm_opts[i]);
    if (!j_string_arg) {
        mrb_raise(mrb, E_ARGUMENT_ERROR, "NewStringUTF() failed");
    }
    (*env)->SetObjectArrayElement(env, main_args, i, j_string_arg);
  }
  //...
}

在某些情况下,成功地调用了SetObjectArrayElement,然后在循环的第三次迭代中始终失败(当i = 2时).当我在mjruby中使用此项目的库时,就会发生这种情况.我也无法解释.

There are also cases where the call is made to SetObjectArrayElement successfully, and then it consistently fails on the third iteration of the loop (when i=2). This happens when I consume this project a library in mjruby. I can't explain that either.

完整的项目在mruby-jvm中的Github上 .

The complete project is on Github in mruby-jvm.

错误详细信息:

Problem signature:
  Problem Event Name:   APPCRASH
  Application Name: mruby-jvm.exe
  Application Version:  0.0.0.0
  Application Timestamp:    55eb01a5
  Fault Module Name:    mruby-jvm.exe
  Fault Module Version: 0.0.0.0
  Fault Module Timestamp:   55eb01a5
  Exception Code:   c0000005
  Exception Offset: 0003fff2
  OS Version:   6.1.7601.2.1.0.256.4
  Locale ID:    1033
  Additional Information 1: 0a9e
  Additional Information 2: 0a9e372d3b4ad19135b953a78882e789
  Additional Information 3: 0a9e
  Additional Information 4: 0a9e372d3b4ad19135b953a78882e789

有没有办法收集有关该错误的更多信息?

Is there a way to collect more information on the error?

它可以在Linux和Mac上完美运行.

It works perfectly on Linux and Mac.

我已包含有关如何在此Github问题中重现该问题的说明.

编辑

我需要澄清的是,我已尽一切可能对此进行了检查.我检查了各种参数是否不为NULL.我什至将几乎整个程序都压缩为:

I should clarify that I've examined this every way I can. I've checked that the various args are not NULL. I even get condensed almost the entire program to this:

static void
jvm_wtf(const char *java_dl, const char *jli_dl) {
  JavaVM *jvm;
  JNIEnv *env;
  JavaVMInitArgs jvm_init_args;
  CreateJavaVM_t* createJavaVM = NULL;

  jvm_init_args.nOptions = 0;
  jvm_init_args.version = JNI_VERSION_1_4;
  jvm_init_args.ignoreUnrecognized = JNI_FALSE;

#if defined(_WIN32) || defined(_WIN64)
  disable_folder_virtualization(GetCurrentProcess());
  HMODULE jvmdll = LoadLibrary(java_dl);
  createJavaVM = (CreateJavaVM_t*) GetProcAddress(jvmdll, "JNI_CreateJavaVM");
#elif defined(__APPLE__)
  // jli needs to be loaded on OSX because otherwise the OS tries to run the system Java
  void *libjli = dlopen(jli_dl, RTLD_NOW + RTLD_GLOBAL);
  void *libjvm = dlopen(java_dl, RTLD_NOW + RTLD_GLOBAL);
  createJavaVM = (CreateJavaVM_t*) dlsym(libjvm, "JNI_CreateJavaVM");
#else
  void *libjvm = dlopen(java_dl, RTLD_NOW + RTLD_GLOBAL);
  createJavaVM = (CreateJavaVM_t*) dlsym(libjvm, "JNI_CreateJavaVM");
#endif
printf("Begining\n");
  createJavaVM(&jvm, (void**)&env, &jvm_init_args);
  jclass main_class = (*env)->FindClass(env, "Main");
  jmethodID main_method = (*env)->GetStaticMethodID(env, main_class, "main", "([Ljava/lang/String;)V");
  jclass j_class_string = (*env)->FindClass(env, "java/lang/String");
  jstring j_string_arg = (*env)->NewStringUTF(env, "");
printf("Checking for NULL\n");
  if (!createJavaVM) { printf("createJavaVM is NULL\n");}
  if (!main_class) { printf("main_class is NULL\n");}
  if (!main_method) { printf("main_method is NULL\n");}
  if (!j_class_string) { printf("j_class_string is NULL\n");}
  if (!j_string_arg) { printf("j_string_arg is NULL\n");}
printf("Right before segfault\n");
  jobjectArray main_args = (*env)->NewObjectArray(env, 1, j_class_string, j_string_arg);
printf("It won't get here\n");
  (*env)->SetObjectArrayElement(env, main_args, 0, (*env)->NewStringUTF(env, "1"));
  (*env)->CallStaticVoidMethod(env, main_class, main_method, main_args);
}

现在,我在NewObjectArray遇到了段错误.进行一些谷歌搜索使我相信,这可能是Windows终止程序的结果,因为它认为JVM的内存分配是恶意的.我该如何确定这是真的?

Now I get a segfault at NewObjectArray. Some googling has led me to believe that this may result from Windows terminating the program because it thinks the memory allocation by the JVM is malicious. How would I determine if this is true?

推荐答案

我不知道为什么,但是在LoadLibrary调用之前声明此变量可以解决此问题.

I have no idea why, but declaring this variable before the LoadLibrary call fixes the problem.

char stupid_var_that_means_nothing_but_makes_windows_work_i_dont_even[MAX_PATH];
HMODULE jvmdll = LoadLibrary(java_dl);

注释该行会导致问题再次开始发生.我也尝试过对其进行调整(更改[]中的值)无济于事.我完全陷入了困境.在尝试从 jruby-添加一些代码后,我偶然发现了这一点启动器

Commenting that line out causes the problem to start happening again. I've also tried adjusting it (changing the value in []) to no avail. I am completely stumped. I stumbled on this by accident after trying to add some code from jruby-launcher

这是我的JNI的完整实现代码.

我讨厌计算机.

这篇关于为什么此JNI仅在Windows上调用segfault?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆