tags:

views:

135

answers:

1

Hello all,

I have a problem with JNI that has taken me all day and will probably drive me insane if I don't call for help.

In two phrases: I call a NewObject from a JNI method and it works fine, but when I moved this code to another method, it crashes.

More details:

I have this simple class, and I want to create instances of it from the JNI C/C++ code:

package example;

public class ModelDetails {
    public ModelDetails() { ... }
}

The class with the native method is as follows:

package example;
public class JNIWrapper {
     public native ModelDetails getModelDetails() throws SomeException;
}

The following code worked very nicely:

jclass    modelDetailsClass           = NULL;
jmethodID modelDetailsConstMid        = NULL;

JNIEXPORT jobject JNICALL Java_example_JNIWrapper_getModelDetails
 (JNIEnv *env, jobject jobj) {

    cout << "getModelDetails c++" << endl;

    // ModelDetails class
    if (!modelDetailsClass) { // reuse class
        modelDetailsClass = env->FindClass("example/ModelDetails");
    }
    if (!modelDetailsClass) { // check if findclass was successful
        throwJavaException(env, "Could not get class ModelDetails");
        return NULL;
    }
    cout << "model detail class: " << modelDetailsClass << endl;

    // constructor
    if (!modelDetailsConstMid) { // reuse method id
        modelDetailsConstMid = env->GetMethodID(modelDetailsClass, "<init>", "()V");
    }
    if (!modelDetailsConstMid) { // check if getmethodid was successful
        throwJavaException(env, "Could not get ModelDetails constructor method id");
        return NULL;
    }

    // create object
    jobject mdetails = env->NewObject(modelDetailsClass, modelDetailsConstMid);
    if (!mdetails) {
        throwJavaException(env, "Could not create ModelDetails instance");
        return NULL;
    }
    return mdetails;
}

However, since I have to do a lot of things in this function Java_example_JNIWrapper_getModelDetails, I decided to move the creation of this object to another function:

jobject fillModelDetails(JNIEnv *env, jobject jobj) {
    cout << "fillModelDetails" << endl;

    // ModelDetails class
    if (!modelDetailsClass) { // reuse class
        modelDetailsClass = env->FindClass("example/ModelDetails");
    }
    if (!modelDetailsClass) { // check if findclass was successful
        throwJavaException(env, "Could not get class ModelDetails");
        return NULL;
    }
    cout << "model detail class: " << modelDetailsClass << endl;

    // constructor
    if (!modelDetailsConstMid) { // reuse method id
        modelDetailsConstMid = env->GetMethodID(modelDetailsClass, "<init>", "()V");
    }
    if (!modelDetailsConstMid) { // check if getmethodid was successful
        throwJavaException(env, "Could not get ModelDetails constructor method id");
        return NULL;
    } 

    // create object
    jobject mdetails = env->NewObject(modelDetailsClass, modelDetailsConstMid);
    if (!mdetails) {
        throwJavaException(env, "Could not create ModelDetails instance");
        return NULL;
    }

    return mdetails;
}

This way, in Java_example_JNIWrapper_getModelDetails I just call fillModelDetails(env, jobj);

The problem is that now I get a bus error at the NewObject line.

Invalid memory access of location 0x9 eip=0x475fe1

Question: Does anyone know why I should not be calling a constructor from another method? It seems really weird.

Thanks for any tip, idea, comments...


Edit:

I've just added -Xcheck:jni and got this error:

FATAL ERROR in native method: Bad global or local ref passed to JNI
at example.JNIWrapper.getModelDetails(Native Method)

So this gave me the idea that the problem might be caused by using the constructor and class id from a global variable. I moved these declarations to a local variable in the JNI method and it works.

This really astonishes me because I've been using these global variables from some time now and never had any problems... what could be causing this problem?

+2  A: 

I will answer this since I found the problem, however another question remains regarding re-using the jclass and jmethodID. Changing this question in that direction does not seem organized, so I will open another thread.

The solution was to use local variables for

jclass    modelDetailsClass           = NULL;
jmethodID modelDetailsConstMid        = NULL;

instead of the global variables that I was using before.

YuppieNetworking