free() 上的 SIGSEGV

发布于 2024-10-19 21:41:21 字数 8424 浏览 1 评论 0原文

我正在移植一个C程序。

我遇到的问题是 free() 上的 SIGSEGV。我看不出其根本原因是什么。似乎堆内存已被某些东西损坏。 它有时不会发生,但经常发生。

malloc 没有返回 NULL。所以内存可能分配正确。

我正在 NexusOne 2.2.1 上测试它 我正在使用 Android NDK r5b 和 Android SDK 以及 Eclipse ADT 和 Cygwin。 我正在使用 android.content.res.AssetFileDescriptor 读取 C 模块中的资源。

这是出现问题时 ndk-gdb 中的消息。

(gdb) c
Continuing.

Breakpoint 2, Java_kr_co_pkbio_Unse_DangSaJuShinSal (env=0xaa50,
    obj=0x4495b970)
    at C:/DEWR/Product/Software-Engineering/Eclipse-Workspace/Unse/jni/unse.c:1
83
1083                    free(strBuf);
(gdb) next

Program received signal SIGSEGV, Segmentation fault.
0xafd11c80 in __libc_android_abort ()
   from C:/DEWR/Product/Software-Engineering/Eclipse-Workspace/Unse/obj/local/a
meabi/libc.so
(gdb) bt
#0  0xafd11c80 in __libc_android_abort ()
   from C:/DEWR/Product/Software-Engineering/Eclipse-Workspace/Unse/obj/local/a
meabi/libc.so
#1  0xbec233bc in ?? ()
Cannot access memory at address 0xc
(gdb) quit

这是Java源代码...

public static HashMap<String, FileInfoForNativeCode> fifnMap = new HashMap<String, FileInfoForNativeCode>();
public static FileInfoForNativeCode openAssets(String fname) {
    FileInfoForNativeCode fifn;

    if (Constants.VERBOSE_LOGS)
        Log.d("TAGG", "TAGG openAssets("+fname+")");

    fifn = fifnMap.get(fname);
    if (fifn != null)
        return fifn;

    AssetFileDescriptor myDescriptor = null;
    try {
        myDescriptor = assetManager.openFd(fname+".jet");
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
    FileDescriptor fd = myDescriptor.getFileDescriptor();
    long off = myDescriptor.getStartOffset();
    long len = myDescriptor.getLength();

    if (Constants.VERBOSE_LOGS)
        Log.d("TAGG", "TAGG fd:"+fd+" off:"+off+" len:"+len);

    fifn = new FileInfoForNativeCode(off, len, fd, myDescriptor);
    fifnMap.put(fname, fifn);
    return fifn;
}

这是C源代码...

char* getTextByIndex (TextFileBufType *filebuf, char *index) {
    #define _INDEX_PREFIX_    '@'
    int        i, j, lenBuf;
    char    *result;
    char    indexPrefix = _INDEX_PREFIX_;
    int        lenIndexPrefix = utf8len( &indexPrefix );
    int        lenIndex = strlen(index);

    for ( i = 0 ; i < filebuf->total ; i++ ) {
        //__android_log_print(ANDROID_LOG_DEBUG,"TAG", "JNI : %d -> %s", i, filebuf->text[i]);

        if ( memcmp (filebuf->text[i], &indexPrefix, lenIndexPrefix) != 0 )
            continue;

        if ( memcmp (filebuf->text[i]+lenIndexPrefix, index, lenIndex) != 0 )
            continue;

        lenBuf = 0;
        lenBuf += strlen(filebuf->text[i]);
        lenBuf++;
        for ( j = i+1 ; j < filebuf->total ; j++ ) {
            if ( memcmp (filebuf->text[j], &indexPrefix, lenIndexPrefix) == 0 )
                break;

            lenBuf += strlen(filebuf->text[j]);
            lenBuf++;
        }

        result = malloc(lenBuf);
        result[0] = 0;
        strcat(result, filebuf->text[i]);
        strcat(result, "\n");
        for ( j = i+1 ; j < filebuf->total ; j++ ) {
            if ( memcmp (filebuf->text[j], &indexPrefix, lenIndexPrefix) == 0 )
                break;

            strcat(result, filebuf->text[j]);
            strcat(result, "\n");
        }

        //__android_log_print(ANDROID_LOG_DEBUG,"TAG", "JNI : %d!!! -> %s", i, filebuf->text[i]);
        return result;
    }

    return NULL;

    #undef _INDEX_PREFIX_
}

inline void readyFileInFile (FileInFile *fif, char *path)
{
    jstring jstrFpath;
    jobject finfo;
    jobject descriptor;

    jstrFpath = (*gEnv)->NewStringUTF(gEnv, path);
    finfo = (*gEnv)->CallStaticObjectMethod(gEnv, clsUtility, midOpenAssets, jstrFpath);
    fif->offset = (*gEnv)->GetLongField(gEnv, finfo, fidOffset);
    fif->length = (*gEnv)->GetLongField(gEnv, finfo, fidLength);
    descriptor = (*gEnv)->GetObjectField(gEnv, finfo, fidDescriptor);
    fif->fd = (*gEnv)->GetIntField(gEnv, descriptor, fidDescriptorFileDescriptor);
}

jobjectArray Java_kr_co_pkbio_Unse_DangSaJuShinSal (JNIEnv *env, jobject obj) {
//    char   *fname = "DangSaJu_ShinSal";
    int     i, fileno[4], ret_code, type;
    char    temp[256];
    char   *header[4] = { "년", "월", "일", "시" };
    char    table1[12] = { 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2 };
    char    table2[4]  = {10, 7, 4, 1};

    char   *index[12] = {
        "겁살",   "재살",   "천살",   "지살",   "연살",   "월살",
        "망신살", "장성살", "반안살", "역마살", "육해살", "화개살"
    };

    int        r_option;
    int        numBytesRead;
    char    *strBuf;
    TextFileBufType    filebuf;
    jstring buf_output[4];
    jobjectArray output;
    FileInFile fif;

    gEnv = env;

    /* 년월일시에 대한 겁살을 계산한다 */
    type = table1[BaseInfo.saju.day % 12];
    fileno[0] = (table2[type] + (BaseInfo.saju.year  % 12)) % 12;
    fileno[1] = (table2[type] + (BaseInfo.saju.month % 12)) % 12;
    fileno[2] = (table2[type] + (BaseInfo.saju.day   % 12)) % 12;
    fileno[3] = (table2[type] + (BaseInfo.saju.hour  % 12)) % 12;
    /*WriteMsg (" - 기본위치 : 생일지지(%s) --> type:%d --> 자(%s)에 대한 살:%s\n",
        JeeJeeStr[BaseInfo.saju.day % 12], type, JeeJeeStr[0], index[table2[type]]);
    WriteMsg (" - 년살     : 생년지지(%s) --> 년%s\n", JeeJeeStr[BaseInfo.saju.year % 12],
        index[fileno[0]]);
    WriteMsg (" - 월살     : 생월지지(%s) --> 월%s\n", JeeJeeStr[BaseInfo.saju.month % 12],
        index[fileno[1]]);
    WriteMsg (" - 일살     : 생일지지(%s) --> 일%s\n", JeeJeeStr[BaseInfo.saju.day % 12],
        index[fileno[2]]);
    WriteMsg (" - 시살     : 생시지지(%s) --> 시%s\n", JeeJeeStr[BaseInfo.saju.hour % 12],
        index[fileno[3]]);*/


    readyFileInFile(&fif, "data/DangSaJu5.dat");

    r_option = ((int)'#' << 8) & 0xFF00;   /* Comment char setting */
    r_option |= (RT_OPT_RMCMT | RT_OPT_RMCRLF | RT_OPT_LTRIM | RT_OPT_RTRIM | RT_OPT_SPACES);

    if ( ReadTextFileToBufA (&filebuf, &fif, r_option) < 0 ) {
        __android_log_print(ANDROID_LOG_ERROR,"TAG", "JNI : 서버측에서 치명적인 오류가 발생하여 더이상 진행할 수 없습니다.");
        return NULL;
    }

    for ( i = 0 ; i < 4 ; i++ ) {
        sprintf (temp, "%s%s", header[i], index[fileno[i]]);
        strBuf = getTextByIndex(&filebuf, temp);
        //__android_log_print(ANDROID_LOG_DEBUG,"TAG", "JNI : %s -> %s", temp, strBuf );
        buf_output[i] = (*gEnv)->NewStringUTF(gEnv, strBuf);
        free(strBuf); //line number : 1083 ***It doesn't cause SIGSEGV on first for-loop-round, but on third for-round.***
        //PrintTextFile3 ("../data/DangSaJu5.dat", temp, VIEW_T_R_STR,
        //    "12신살로 알아보는 인생의 길흉화복 : %s", temp);
        /*if (i < 3) {
            sprintf (temp, "\n 계속해서 %s%s에 대한 풀이를 보시겠습니까? (Y/n)",
                header[i+1], index[fileno[i+1]]);
            ret_code = GetYesNo (temp, GETYN_YES);
            if (ret_code == GETYN_NO)  return;
        }*/
    }

    FreeTextFileBuf (&filebuf);
    //printf ("\n [Enter]키를 누르세요.");  fflush(stdout);
    //PauseUntil (300, 0);
    #if defined (_DO_NOT_COMPILE_)
    {
        int j;
        for (i=0 ; i<4 ; i++) {
            for (j=0 ; j<12 ; j++) {
                sprintf (temp, "%s%s", header[i], index[j]);
                //PrintTextFile3 ("../data/DangSaJu5.dat", temp, VIEW_T_R_STR,
                //    "당사주 / 인생 길흉화복 datafile test : %s", temp);
            }
        }
    }
    #endif

    output = (*gEnv)->NewObjectArray(gEnv, 4, clsString, NULL);
    (*gEnv)->SetObjectArrayElement(gEnv, output, 0, buf_output[0]);
    (*gEnv)->SetObjectArrayElement(gEnv, output, 1, buf_output[1]);
    (*gEnv)->SetObjectArrayElement(gEnv, output, 2, buf_output[2]);
    (*gEnv)->SetObjectArrayElement(gEnv, output, 3, buf_output[3]);

    return output;
}

我正在控制AssetFileDescriptors的生命周期。我不使用终止的文件描述符。 我是否必须在 Java 中重新编码 I/O 例程,或者不释放分配的内存? 它通常会在第三个 for 循环上导致 SIGSEGV。但有时在第四循环。

    for ( i = 0 ; i < 4 ; i++ ) {
        sprintf (temp, "%s%s", header[i], index[fileno[i]]);
        strBuf = getTextByIndex(&filebuf, temp); //malloc() in this function.
        if (strBuf == NULL)
            buf_output[i] = NULL;
        else

        {
            buf_output[i] = (*gEnv)->NewStringUTF(gEnv, strBuf);
            free(strBuf);
        }
    }

I am porting a C program.

The problem I've met is SIGSEGV on free(). I can't see what's the root cause of it. it seems like heap-memory has corrupted by something.
it doesn't occur sometimes, but very often.

malloc didn't return NULL. so memories maybe allocated correctly.

I am testing it on NexusOne 2.2.1
I am using Android NDK r5b and Android SDK and Eclipse ADT and Cygwin.
I am using android.content.res.AssetFileDescriptor to read assets in C modules.

Here is the messages in ndk-gdb when the problem appears.

(gdb) c
Continuing.

Breakpoint 2, Java_kr_co_pkbio_Unse_DangSaJuShinSal (env=0xaa50,
    obj=0x4495b970)
    at C:/DEWR/Product/Software-Engineering/Eclipse-Workspace/Unse/jni/unse.c:1
83
1083                    free(strBuf);
(gdb) next

Program received signal SIGSEGV, Segmentation fault.
0xafd11c80 in __libc_android_abort ()
   from C:/DEWR/Product/Software-Engineering/Eclipse-Workspace/Unse/obj/local/a
meabi/libc.so
(gdb) bt
#0  0xafd11c80 in __libc_android_abort ()
   from C:/DEWR/Product/Software-Engineering/Eclipse-Workspace/Unse/obj/local/a
meabi/libc.so
#1  0xbec233bc in ?? ()
Cannot access memory at address 0xc
(gdb) quit

Here is the Java source code...

public static HashMap<String, FileInfoForNativeCode> fifnMap = new HashMap<String, FileInfoForNativeCode>();
public static FileInfoForNativeCode openAssets(String fname) {
    FileInfoForNativeCode fifn;

    if (Constants.VERBOSE_LOGS)
        Log.d("TAGG", "TAGG openAssets("+fname+")");

    fifn = fifnMap.get(fname);
    if (fifn != null)
        return fifn;

    AssetFileDescriptor myDescriptor = null;
    try {
        myDescriptor = assetManager.openFd(fname+".jet");
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
    FileDescriptor fd = myDescriptor.getFileDescriptor();
    long off = myDescriptor.getStartOffset();
    long len = myDescriptor.getLength();

    if (Constants.VERBOSE_LOGS)
        Log.d("TAGG", "TAGG fd:"+fd+" off:"+off+" len:"+len);

    fifn = new FileInfoForNativeCode(off, len, fd, myDescriptor);
    fifnMap.put(fname, fifn);
    return fifn;
}

Here is the C source code...

char* getTextByIndex (TextFileBufType *filebuf, char *index) {
    #define _INDEX_PREFIX_    '@'
    int        i, j, lenBuf;
    char    *result;
    char    indexPrefix = _INDEX_PREFIX_;
    int        lenIndexPrefix = utf8len( &indexPrefix );
    int        lenIndex = strlen(index);

    for ( i = 0 ; i < filebuf->total ; i++ ) {
        //__android_log_print(ANDROID_LOG_DEBUG,"TAG", "JNI : %d -> %s", i, filebuf->text[i]);

        if ( memcmp (filebuf->text[i], &indexPrefix, lenIndexPrefix) != 0 )
            continue;

        if ( memcmp (filebuf->text[i]+lenIndexPrefix, index, lenIndex) != 0 )
            continue;

        lenBuf = 0;
        lenBuf += strlen(filebuf->text[i]);
        lenBuf++;
        for ( j = i+1 ; j < filebuf->total ; j++ ) {
            if ( memcmp (filebuf->text[j], &indexPrefix, lenIndexPrefix) == 0 )
                break;

            lenBuf += strlen(filebuf->text[j]);
            lenBuf++;
        }

        result = malloc(lenBuf);
        result[0] = 0;
        strcat(result, filebuf->text[i]);
        strcat(result, "\n");
        for ( j = i+1 ; j < filebuf->total ; j++ ) {
            if ( memcmp (filebuf->text[j], &indexPrefix, lenIndexPrefix) == 0 )
                break;

            strcat(result, filebuf->text[j]);
            strcat(result, "\n");
        }

        //__android_log_print(ANDROID_LOG_DEBUG,"TAG", "JNI : %d!!! -> %s", i, filebuf->text[i]);
        return result;
    }

    return NULL;

    #undef _INDEX_PREFIX_
}

inline void readyFileInFile (FileInFile *fif, char *path)
{
    jstring jstrFpath;
    jobject finfo;
    jobject descriptor;

    jstrFpath = (*gEnv)->NewStringUTF(gEnv, path);
    finfo = (*gEnv)->CallStaticObjectMethod(gEnv, clsUtility, midOpenAssets, jstrFpath);
    fif->offset = (*gEnv)->GetLongField(gEnv, finfo, fidOffset);
    fif->length = (*gEnv)->GetLongField(gEnv, finfo, fidLength);
    descriptor = (*gEnv)->GetObjectField(gEnv, finfo, fidDescriptor);
    fif->fd = (*gEnv)->GetIntField(gEnv, descriptor, fidDescriptorFileDescriptor);
}

jobjectArray Java_kr_co_pkbio_Unse_DangSaJuShinSal (JNIEnv *env, jobject obj) {
//    char   *fname = "DangSaJu_ShinSal";
    int     i, fileno[4], ret_code, type;
    char    temp[256];
    char   *header[4] = { "년", "월", "일", "시" };
    char    table1[12] = { 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3, 2 };
    char    table2[4]  = {10, 7, 4, 1};

    char   *index[12] = {
        "겁살",   "재살",   "천살",   "지살",   "연살",   "월살",
        "망신살", "장성살", "반안살", "역마살", "육해살", "화개살"
    };

    int        r_option;
    int        numBytesRead;
    char    *strBuf;
    TextFileBufType    filebuf;
    jstring buf_output[4];
    jobjectArray output;
    FileInFile fif;

    gEnv = env;

    /* 년월일시에 대한 겁살을 계산한다 */
    type = table1[BaseInfo.saju.day % 12];
    fileno[0] = (table2[type] + (BaseInfo.saju.year  % 12)) % 12;
    fileno[1] = (table2[type] + (BaseInfo.saju.month % 12)) % 12;
    fileno[2] = (table2[type] + (BaseInfo.saju.day   % 12)) % 12;
    fileno[3] = (table2[type] + (BaseInfo.saju.hour  % 12)) % 12;
    /*WriteMsg (" - 기본위치 : 생일지지(%s) --> type:%d --> 자(%s)에 대한 살:%s\n",
        JeeJeeStr[BaseInfo.saju.day % 12], type, JeeJeeStr[0], index[table2[type]]);
    WriteMsg (" - 년살     : 생년지지(%s) --> 년%s\n", JeeJeeStr[BaseInfo.saju.year % 12],
        index[fileno[0]]);
    WriteMsg (" - 월살     : 생월지지(%s) --> 월%s\n", JeeJeeStr[BaseInfo.saju.month % 12],
        index[fileno[1]]);
    WriteMsg (" - 일살     : 생일지지(%s) --> 일%s\n", JeeJeeStr[BaseInfo.saju.day % 12],
        index[fileno[2]]);
    WriteMsg (" - 시살     : 생시지지(%s) --> 시%s\n", JeeJeeStr[BaseInfo.saju.hour % 12],
        index[fileno[3]]);*/


    readyFileInFile(&fif, "data/DangSaJu5.dat");

    r_option = ((int)'#' << 8) & 0xFF00;   /* Comment char setting */
    r_option |= (RT_OPT_RMCMT | RT_OPT_RMCRLF | RT_OPT_LTRIM | RT_OPT_RTRIM | RT_OPT_SPACES);

    if ( ReadTextFileToBufA (&filebuf, &fif, r_option) < 0 ) {
        __android_log_print(ANDROID_LOG_ERROR,"TAG", "JNI : 서버측에서 치명적인 오류가 발생하여 더이상 진행할 수 없습니다.");
        return NULL;
    }

    for ( i = 0 ; i < 4 ; i++ ) {
        sprintf (temp, "%s%s", header[i], index[fileno[i]]);
        strBuf = getTextByIndex(&filebuf, temp);
        //__android_log_print(ANDROID_LOG_DEBUG,"TAG", "JNI : %s -> %s", temp, strBuf );
        buf_output[i] = (*gEnv)->NewStringUTF(gEnv, strBuf);
        free(strBuf); //line number : 1083 ***It doesn't cause SIGSEGV on first for-loop-round, but on third for-round.***
        //PrintTextFile3 ("../data/DangSaJu5.dat", temp, VIEW_T_R_STR,
        //    "12신살로 알아보는 인생의 길흉화복 : %s", temp);
        /*if (i < 3) {
            sprintf (temp, "\n 계속해서 %s%s에 대한 풀이를 보시겠습니까? (Y/n)",
                header[i+1], index[fileno[i+1]]);
            ret_code = GetYesNo (temp, GETYN_YES);
            if (ret_code == GETYN_NO)  return;
        }*/
    }

    FreeTextFileBuf (&filebuf);
    //printf ("\n [Enter]키를 누르세요.");  fflush(stdout);
    //PauseUntil (300, 0);
    #if defined (_DO_NOT_COMPILE_)
    {
        int j;
        for (i=0 ; i<4 ; i++) {
            for (j=0 ; j<12 ; j++) {
                sprintf (temp, "%s%s", header[i], index[j]);
                //PrintTextFile3 ("../data/DangSaJu5.dat", temp, VIEW_T_R_STR,
                //    "당사주 / 인생 길흉화복 datafile test : %s", temp);
            }
        }
    }
    #endif

    output = (*gEnv)->NewObjectArray(gEnv, 4, clsString, NULL);
    (*gEnv)->SetObjectArrayElement(gEnv, output, 0, buf_output[0]);
    (*gEnv)->SetObjectArrayElement(gEnv, output, 1, buf_output[1]);
    (*gEnv)->SetObjectArrayElement(gEnv, output, 2, buf_output[2]);
    (*gEnv)->SetObjectArrayElement(gEnv, output, 3, buf_output[3]);

    return output;
}

I am controlling lifetime of AssetFileDescriptors. I don't use terminated FileDescriptors.
Do I have to re-code I/O routines in Java or not to free allocated memories?
it often causes SIGSEGV on third for-loop. but sometimes on fourth loop.

    for ( i = 0 ; i < 4 ; i++ ) {
        sprintf (temp, "%s%s", header[i], index[fileno[i]]);
        strBuf = getTextByIndex(&filebuf, temp); //malloc() in this function.
        if (strBuf == NULL)
            buf_output[i] = NULL;
        else

        {
            buf_output[i] = (*gEnv)->NewStringUTF(gEnv, strBuf);
            free(strBuf);
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

酒中人 2024-10-26 21:41:21

我已经在 Galaxy S 上进行了测试,它在 Galaxy S (2.2) 上运行良好。我还没有在另一台 Nexus One 上尝试过,以确定我的 Nexus One 是否有故障。

似乎 AssetFileDescriptor 不是问题的根源,因为当我没有直接访问资产文件而是访问复制的资产文件时,问题仍然发生。

I have tested it on Galaxy S and it worked well on Galaxy S (2.2). I have not tried it on another Nexus One in order to know if my Nexus One is faulty.

and it seems like that AssetFileDescriptor is not the source of the problem, because the problem is still ocurring while I didn't access asset files directly but accessing copied ones.

倒带 2024-10-26 21:41:21

我通过将这 1 行代码放在 free(strBuf); 之后进行调试。 (虽然没有重复的 free(strBuf)...)

strBuf = NULL;

I have debugged by putting this 1 line code right after free(strBuf); (though there is no repeating free(strBuf)...)

strBuf = NULL;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文