1. ホーム
  2. アンドロイド

jni error "@@@@ ABORTING: INVALID HEAP ADDRESS IN dlfree" (無効なヒープアドレス)

2022-03-02 13:50:25

     まず、コードの一部を見てください。

typedef WORD unsigned short;
JNIEXPORT jobject XXX_getString(JNIEnv* env, jobject thiz, jint file,jobject head,jobject word,jint index)
{
	jobject jstr = NULL;

	int i = 0,j,len;
    WORD *buf;
    int adr = (*env)->GetIntField(env,word,wd_ExplainAddress);
    len = getWordStartAddress(file,index + 1,(*env)->GetIntField(env,head,dh_CodeAddressTable)) - adr;
    
    buf = (WORD*)malloc(len + 2);
    if(buf == NULL){
        return NULL;
    }

    lseek(file,adr,SEEK_SET);
    read(file,buf,len);

    buf[len / 2 + 1] = 0;
    while(buf[i]){
        if((buf[i] >= 0xF800) &&(buf[i] <= 0xF8FF) || (buf[i] >= 0xF700) &&(buf[i] <= 0xF70D)){
            j = i;
            while(buf[j]){
                buf[j] = buf[j + 1];
                j++;
            }
            continue;
        }
        i++;
    }
    buf[i] = 0;
    jstr = (*env)->NewString(env,buf,i);
    free(buf);
    return jstr;
}

これは上記のコードですが、1行に問題があり、エラー "@@@@ ABORTING: INVALID HEAP ADDRESS IN dlfree"

このエラーは、メモリにエラーがあること、そしてそのエラーがfree、つまり上記の33行目にあることを示しています。しかし、mallocメモリにエラーがあるか、freeのアドレスが間違っているか、mallocメモリが圏外にアクセスされたのでなければ、どうしてfreeにエラーがあるのだろうか。一見して、bufアドレスは変わっていないので、アドレスが間違っているはずはないのである。では、具体的にどのようにして圏外になったのでしょうか?

bufのポインタはWORDで、(len+2)バイト割り当てられているので、最低でも2バイトあり、さらにbuf[len/2+1]=0で、最後に割り当てられたWORDを0にする。 だから20、23行目のwhile文も範囲外にはならない。では、具体的にはどこなのでしょうか?lenが0より小さいとうまくいかないと言うかもしれませんが、このlenは計算されているので、論理的に除外されています。じゃあ、lenも0以下にはならないし、whileループもアウトオブバウンズにはならないのに、どうしてまだ間違いがあるのでしょうか?

よく見てください、lenが3のような奇数の場合、buf = malloc(3+2), bufは5バイト、19行目、 buf[3/2+1] = buf[2] = 0, なぜならbufはWORD型、1要素2バイトです。 buf[2]はbufの先頭から5バイト目と6バイト目、つまり割り当てられたbufは5バイトしかなく、これから6バイト目にアクセスするため、圏外になる。

テストの結果、9行目で得られるlenは常に偶数であり、奇数の場合はないが、それでも同じエラーが出るので、これはメモリアライメントの問題に属する。メモリアライメントについては、Web上に多くの情報がありますので、参考までにURLを記載しておきます。

メモリーアライメント規則とその効果

すみません、上の取り消し線のある段落は実は間違っています。このブログを読んでいる人がどれだけいるか分かりませんし、誤解を与えてしまって申し訳ありません