2011-02-28 6 views
0

C 프로그램을 포팅 중입니다.무료 SIGSEGV()

내가 만난 문제는 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 

여기 ... 여기

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의 수명을 제어하고있는 자바 소스 코드입니다. 나는 종결 된 FileDescriptor를 사용하지 않는다. Java에서 I/O 루틴을 다시 코딩해야합니까, 아니면 할당 된 메모리를 확보하지 않아야합니까? 세 번째 for-loop에서 종종 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); 
     } 
    } 
+0

왜'char * indexPrefix'가 아닌'char indexPrefix'입니까? 하나의 종결되지 않은 문자에 'utf8len'을 부르는 것은 이상하게 보입니다. – sarnold

+0

@sarnold utf8len은 ndk에 없었으므로 혼자서 만들었습니다. 내 utf8len() 문자열에 대한 아니지만 그것은 문자의 바이트 길이를 계산하는 일이다. – Dewr

답변

0

무료 (strBuf) 바로 뒤에이 1 줄 코드를 삽입하여 디버깅했습니다. (반복적 인 free (strBuf)는 없지만 ...)

strBuf = NULL; 
0

저는 갤럭시 S에서 테스트 해 보았는데 갤럭시 S (2.2)에서 잘 작동했습니다. Nexus One에 결함이 있는지 확인하기 위해 다른 Nexus One에서 시도하지 않았습니다.

AssetFileDescriptor가 문제의 원인이 아닌 것처럼 보입니다. 애셋 파일에 직접 액세스하지 않고 복사 된 파일에 액세스하는 동안 문제가 여전히 발생하기 때문입니다.

관련 문제