我正在移植一个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的生命周期。我不使用终止的FileDescriptors。 我是否必须使用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);
}
}
答案 0 :(得分:0)
我在Galaxy S上测试了它,它在Galaxy S(2.2)上运行良好。我没有在另一台Nexus One上试过,以便知道我的Nexus One是否有问题。
似乎AssetFileDescriptor不是问题的根源,因为问题仍然存在,而我没有直接访问资产文件而是访问复制文件。
答案 1 :(得分:0)
我已经通过将此1行代码放在free(strBuf)之后进行了调试; (虽然没有重复的自由(strBuf)...)
strBuf = NULL;