(* виртуальная машина)-> GetEnv segfaults только на устройствах HTC

#android #segmentation-fault #java-native-interface

#Android #ошибка сегментации #java-родной интерфейс

Вопрос:

В настоящее время я работаю над более крупным проектом с несколькими потоками в собственной среде. Поэтому мне нужен вызов (* vm)-> GetEnv, чтобы получить текущий активный JNIEnv для собственного потока. Потоки подключаются при создании, но я добавил сбой в методе, который вызывает GetEnv:

 void get_jni_env(void **e) {
    JNIEnv *env = malloc(sizeof(JNIEnv *));

    if((*vm)->GetEnv(vm, (void **)amp;env, JNI_VERSION_1_4) != JNI_OK) {
        __android_log_write(ANDROID_LOG_ERROR, "Call to GetEnv from a unattached native thread. Trying to attach thread.");
        if((*vm)->AttachCurrentThread(vm, amp;env, NULL) != JNI_OK) {
            __android_log_write(ANDROID_LOG_ERROR, "Failed to receive any jni environment. Crashing soon");
        }
    }

    *e = env;
}
  

При пошаговом выполнении вы видите, что вызов (*vm)-> GetEnv segfaults выполняется:

 jni_get_long (ctx=0x40525080, key=0x804215e0 "hm") at jni/jni.c:50
50      GET_JNI_ENV(amp;env);
(gdb) s
get_jni_env (e=0xbec603e8) at jni/../../../../core/android/util.c:159
159     if((*vm)->GetEnv(vm, (void **)amp;env, JNI_VERSION_1_4) != JNI_OK) {
(gdb) n
156 void get_jni_env(void **e) {
(gdb) 
157     JNIEnv *env = malloc(sizeof(JNIEnv *));
(gdb) 
159     if((*vm)->GetEnv(vm, (void **)amp;env, JNI_VERSION_1_4) != JNI_OK) {
(gdb) 

Program received signal SIGSEGV, Segmentation fault.
0xaca43510 in ?? ()  ← this is somewhere on the heap
  

Тот же код отлично работает на устройствах Samsung и Sony Ericsson, а также в эмуляторе. У меня немного не хватает идей для этой конкретной ошибки. Я также тестировал устройство HTC с CyanogenMod 7.1, которое должно быть довольно похоже на AOSP Android, и даже там оно выходит из строя в тот же момент.

Ответ №1:

Не могу понять, почему вы меняете свою переменную JNIEnv? Android сделает это за вас. В любом случае, вот мой код, который отлично работает на моем HTC Desire:

 JNIEnv *GetJEnv() {
  JNIEnv *res;
  if (jvm->GetEnv((void **)amp;res,JNI_VERSION_1_6)==JNI_EDETACHED)
    jvm->AttachCurrentThread(amp;res,NULL);
  return res;
}
  

Комментарии:

1. Ну, это можно игнорировать. Я попытался выяснить, было ли это вызвано некоторыми ошибочными адресами в стеке, и переместил адрес с помощью malloc() в кучу. Но проблема, похоже, в другом месте. Ваша версия тоже не будет работать, я уже пробовал ее заранее. Но спасибо, что нашли время ответить.

Ответ №2:

JNIEnv *env = malloc(sizeof(JNIEnv *));

это неправильно.

Он выделяет память, которая может содержать указатель на JNIEnv объект, а не объем памяти для JNIEnv самого объекта.

Это должно быть

 JNIEnv *env = malloc(sizeof(JNIEnv));
  

или даже лучше:

 JNIEnv *env = malloc(sizeof( *env ));
  

«Отлично работает» на других платформах не означает, что это правильно.