OS X Mavericks JNI CallStaticVoidMethod results in SIGSEGV/SIGBUS (Java 8)

566 views Asked by At

I have an C application that runs Java through JNI. The Java application starts, does some stuff and after a second or two I get either SIGSEGV or SIGBUS . There is no java crash dump file.

Here is where it crashes:

libjvm.dylib`jni_CallStaticVoidMethod:
0x104ad1653 <+0>:   pushq  %rbp
0x104ad1654 <+1>:   movq   %rsp, %rbp
0x104ad1657 <+4>:   pushq  %r15
0x104ad1659 <+6>:   pushq  %r14
0x104ad165b <+8>:   pushq  %r12
0x104ad165d <+10>:  pushq  %rbx
0x104ad165e <+11>:  subq   $0x150, %rsp
0x104ad1665 <+18>:  movq   %rdx, %rbx
0x104ad1668 <+21>:  movq   %rsi, %r14
0x104ad166b <+24>:  movq   %rdi, %r15
0x104ad166e <+27>:  testb  %al, %al
0x104ad1670 <+29>:  je     0x104ad16aa               ; <+87>
0x104ad1672 <+31>:  movaps %xmm0, -0x140(%rbp)
0x104ad1679 <+38>:  movaps %xmm1, -0x130(%rbp)
0x104ad1680 <+45>:  movaps %xmm2, -0x120(%rbp)
0x104ad1687 <+52>:  movaps %xmm3, -0x110(%rbp)
0x104ad168e <+59>:  movaps %xmm4, -0x100(%rbp)
0x104ad1695 <+66>:  movaps %xmm5, -0xf0(%rbp)
0x104ad169c <+73>:  movaps %xmm6, -0xe0(%rbp)
0x104ad16a3 <+80>:  movaps %xmm7, -0xd0(%rbp)
0x104ad16aa <+87>:  movq   %r9, -0x148(%rbp)
0x104ad16b1 <+94>:  movq   %r8, -0x150(%rbp)
0x104ad16b8 <+101>: movq   %rcx, -0x158(%rbp)
0x104ad16bf <+108>: movq   %r15, %rdi
0x104ad16c2 <+111>: callq  0x104c8c550               ; JavaThread::thread_from_jni_environment(JNIEnv_*)
0x104ad16c7 <+116>: movq   %rax, %r12
0x104ad16ca <+119>: movq   %r12, -0x28(%rbp)
0x104ad16ce <+123>: leaq   -0x28(%rbp), %rdi
0x104ad16d2 <+127>: movl   $0x6, %esi
0x104ad16d7 <+132>: callq  0x104926aac               ; ThreadStateTransition::trans_from_native(JavaThreadState)
0x104ad16dc <+137>: movq   %r12, -0x30(%rbp)
0x104ad16e0 <+141>: movq   %r12, -0x50(%rbp)
0x104ad16e4 <+145>: movq   $0x0, -0x48(%rbp)
0x104ad16ec <+153>: cmpq   $0x0, 0x8(%r12)
0x104ad16f2 <+159>: je     0x104ad16fd               ; <+170>
0x104ad16f4 <+161>: leaq   -0x50(%rbp), %rdi
0x104ad16f8 <+165>: callq  0x104c5cf7c               ; WeakPreserveExceptionMark::preserve()
0x104ad16fd <+170>: movq   %r14, %rsi
0x104ad1700 <+173>: movq   %r15, %rdi
0x104ad1703 <+176>: movq   %rbx, %rdx
0x104ad1706 <+179>: nop    
0x104ad1707 <+180>: nopl   (%rax)
0x104ad170b <+184>: leaq   -0x170(%rbp), %rax
0x104ad1712 <+191>: movq   %rax, -0x58(%rbp)
0x104ad1716 <+195>: leaq   0x10(%rbp), %rax
0x104ad171a <+199>: movq   %rax, -0x60(%rbp)
0x104ad171e <+203>: movl   $0x30, -0x64(%rbp)
0x104ad1725 <+210>: movl   $0x18, -0x68(%rbp)
0x104ad172c <+217>: movl   $0xe, -0x78(%rbp)
0x104ad1733 <+224>: movq   (%rbx), %rax
0x104ad1736 <+227>: movq   0x8(%rax), %rax
0x104ad173a <+231>: movzwl 0x22(%rax), %ecx
0x104ad173e <+235>: movq   0x8(%rax), %rax
0x104ad1742 <+239>: movq   0x50(%rax,%rcx,8), %rsi
0x104ad1747 <+244>: leaq   -0xb8(%rbp), %r14
0x104ad174e <+251>: movq   %r14, %rdi
0x104ad1751 <+254>: callq  0x104ca2c14               ; SignatureIterator::SignatureIterator(Symbol*)
0x104ad1756 <+259>: movl   $0x63, -0xa0(%rbp)
0x104ad1760 <+269>: movq   $0x0, -0x98(%rbp)
0x104ad176b <+280>: leaq   0x4f827e(%rip), %rax      ; vtable for JNI_ArgumentPusherVaArg
0x104ad1772 <+287>: addq   $0x10, %rax
0x104ad1776 <+291>: movq   %rax, -0xb8(%rbp)
0x104ad177d <+298>: movq   -0x58(%rbp), %rax
0x104ad1781 <+302>: movq   %rax, -0x80(%rbp)
0x104ad1785 <+306>: movq   -0x68(%rbp), %rax
0x104ad1789 <+310>: movq   -0x60(%rbp), %rcx
0x104ad178d <+314>: movq   %rcx, -0x88(%rbp)
0x104ad1794 <+321>: movq   %rax, -0x90(%rbp)
0x104ad179b <+328>: leaq   -0x78(%rbp), %rsi
0x104ad179f <+332>: movq   %r15, %rdi
0x104ad17a2 <+335>: movq   %rbx, %rdx
0x104ad17a5 <+338>: movq   %r14, %rcx
0x104ad17a8 <+341>: movq   %r12, %r8
0x104ad17ab <+344>: callq  0x104ad8877               ; jni_invoke_static(JNIEnv_*, JavaValue*, _jobject*, JNICallType, _jmethodID*, JNI_ArgumentPusher*, Thread*)
0x104ad17b0 <+349>: cmpq   $0x0, 0x8(%r12)
0x104ad17b6 <+355>: jne    0x104ad17bf               ; <+364>
0x104ad17b8 <+357>: nop    
0x104ad17b9 <+358>: nopl   (%rax)
0x104ad17bd <+362>: jmp    0x104ad17c4               ; <+369>
0x104ad17bf <+364>: nop    
0x104ad17c0 <+365>: nopl   (%rax)
0x104ad17c4 <+369>: cmpq   $0x0, -0x48(%rbp)
0x104ad17c9 <+374>: je     0x104ad17d4               ; <+385>
0x104ad17cb <+376>: leaq   -0x50(%rbp), %rdi
0x104ad17cf <+380>: callq  0x104c5cefa               ; WeakPreserveExceptionMark::restore()
0x104ad17d4 <+385>: leaq   -0x30(%rbp), %rdi
0x104ad17d8 <+389>: callq  0x1048ffc80               ; HandleMarkCleaner::~HandleMarkCleaner()
0x104ad17dd <+394>: leaq   -0x28(%rbp), %rdi
0x104ad17e1 <+398>: movl   $0x6, %esi
0x104ad17e6 <+403>: movl   $0x4, %edx
0x104ad17eb <+408>: callq  0x104931e04               ; ThreadStateTransition::trans_and_fence(JavaThreadState, JavaThreadState)
0x104ad17f0 <+413>: addq   $0x150, %rsp
0x104ad17f7 <+420>: popq   %rbx
0x104ad17f8 <+421>: popq   %r12
0x104ad17fa <+423>: popq   %r14
0x104ad17fc <+425>: popq   %r15
0x104ad17fe <+427>: popq   %rbp
0x104ad17ff <+428>: retq   

The debuger points to the line (in the code above):

 0x104ad17b0 <+349>: cmpq   $0x0, 0x8(%r12)

and next points to the first line of this code as the cause (it does not say where is this code from):

->  0x1058e5535: movl   0xc(%rdx), %r10d
    0x1058e5539: movl   0xc(%r12,%r10,8), %ebx
    0x1058e553e: movl   0x10(%rsi), %r8d
    0x1058e5542: movl   0xc(%r12,%r8,8), %r9d
    0x1058e5547: movl   %r9d, 0x14(%rsp)
    0x1058e554c: movl   0xc(%rsi), %r11d
    0x1058e5550: movl   %ebx, %ebp
    0x1058e5552: addl   %r11d, %ebp

As I say, this does not happen immediately - the Java application manages to do a couple things. The crash apparently occurs when I tries to use AWT gui classes. Also, the log shows this line (not sure if this is related):

WARNING: GL pipe is running in software mode (Renderer ID=0x1020400)

Is this a JVM bug? How should I proceed?

EDIT:

The relevant source code:

void* runJava(void* arg) {

        JNIEnv *env;
        JavaVM * jvm;
        int nOptions = 1;

        char jvmLibPath[PATH_MAX];

        if (! jreSearch(jvmLibPath)) {
            return NULL;
        }

        void* handle = dlopen(jvmLibPath, RTLD_LAZY);

        NSLog(@"loaded jvm library %s\n", jvmLibPath);
        if (handle == NULL) {
            NSLog(@"error: %s\n", dlerror());
            exit(EXIT_FAILURE);
        }
        PtrCreateJavaVM ptrCreateJavaVM = (PtrCreateJavaVM) dlsym(handle, "JNI_CreateJavaVM");
        if (ptrCreateJavaVM == NULL) {
            fprintf(stderr, "%s\n", dlerror());
            exit(EXIT_FAILURE);
        }

        JavaVMOption* options = (JavaVMOption*) malloc(sizeof(JavaVMOption) * (nOptions));

        options[0].optionString = "-Djava.class.path=../MyJavaApp.jar";

        JavaVMInitArgs vm_args;
        vm_args.version = JNI_VERSION_1_8;
        vm_args.nOptions = nOptions;
        vm_args.options = options;
        vm_args.ignoreUnrecognized = 0;

        int ret = ptrCreateJavaVM(&jvm, (void**) &env, &vm_args);
        if (ret < 0)
            NSLog(@"\nUnable to Launch JVM\n");

        if (env == NULL) {
            exit(EXIT_FAILURE);
        }

        jclass mainClass = (*env)->FindClass(env, "mainpackage.MyMainClass");

        if (mainClass == 0) {
            NSLog(@"Failed to find class (or it's dependencies)");
        }

        jmethodID mainMethod = (*env)->GetStaticMethodID(env, mainClass, "main", "([Ljava/lang/String;)V");
        if (mainMethod == 0) {
            NSLog(@"Failed to acquire main() method of main class\n");
            exit(EXIT_FAILURE);
        }

        NSArray *args = [[NSProcessInfo processInfo] arguments];
        int argc_ =(int)[args count];
        char** argv_ = getArray(args);

        //application name is not passed to java app, hence (argc - 1)
        jobjectArray appArgs = (*env)->NewObjectArray(env, argc_ - 1,(*env)->FindClass(env, "java/lang/String"), NULL);
        int i;
        for (i = 0; i < argc_ - 1; i = i + 1) {
            //argv[i + 1] skipps application name
            jstring arg = (*env)->NewStringUTF(env, argv_[i + 1]);
            (*env)->SetObjectArrayElement(env, appArgs, i, arg);
        }

        NSLog(@"calling main method\n");
        (*env)->CallStaticVoidMethod(env, mainClass, mainMethod, appArgs);
        NSLog(@"after main method\n");


        (*jvm)->DestroyJavaVM(jvm);
        if (options != NULL) {
            int i;
            for (i = 0; i < nOptions; i++) {
                free(options[i].optionString);
            }
        }

        NSLog(@"JVM destroyed\n");
        freeArray(argv_);

        pthread_mutex_lock(&javaFinishedMutex);
        pthread_cond_signal(&javaFinishedCond);
        pthread_mutex_unlock(&javaFinishedMutex);

        return NULL;
}
1

There are 1 answers

0
ed22 On

Apparently JVM uses SIGBUS/SIGSEGV internally to control the app (?). I made mu debugger pass those signals to the app and everything is fine now.