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);
}
//...
}
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.
The complete project is on Github in mruby-jvm.
Error Details:
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?
It works perfectly on Linux and Mac.
I've included instructions on how to reproduce the problem in this Github issue.
EDIT
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);
}
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?