fclose()导致分段错误

我有一个制表符分隔的文本文件,我正在解析。 其第一列包含格式为chrX字符串,其中X表示一组字符串,例如“1”,“2”,……,“X”,“Y”。

当解析文件时,这些都存储在称为chromosomechar*

文本文件按字典顺序排在第一列,即,我将有一些以“chr1”开头的行,然后是“chr2”等。

在每个“chrX”条目中,我需要打开与此条目关联的另一个文件:

 FILE *merbaseIn; // loop through rows... if (chromosome == NULL) openSourceFile(&chromosome, fieldArray[i], &merbaseIn, GENPATHIN); else { if (strcmp(chromosome, fieldArray[i]) != 0) { // new chromosome fclose(merbaseIn); // close old chromosome FILE ptr free(chromosome); // free old chromosome ptr openSourceFile(&chromosome, fieldArray[i], &merbaseIn, GENPATHIN); // set up new chromosome FILE ptr } } // parse row 

我有openSourceFile函数,定义如下:

 void openSourceFile (char** chrome, const char* field, FILE** filePtr, const char *path) { char filename[100]; *chrome = (char *) malloc ((size_t) strlen(field)); if (*chrome == NULL) { fprintf(stderr, "ERROR: Cannot allocate memory for chromosome name!"); exit(EXIT_FAILURE); } strcpy(*chrome, field); sprintf(filename,"%s%s.fa", path, field); *filePtr = fopen(filename, "r"); if (*filePtr == NULL) { fprintf(stderr, "ERROR: Could not open fasta source file %s\n", filename); exit(EXIT_FAILURE); } } 

问题是我的应用程序在下一行从第一个染色体到第二个染色体(从chr1chr2 )退出分段错误,在那里我关闭了我打开的第一个染色体文件:

 fclose(merbaseIn); 

我知道我没有传递fclose一个NULL指针,因为直到Segmentation Fault,我正在从这个文件中读取数据。 我甚至可以在条件中包装它,我仍然得到错误:

 if (merbaseIn != NULL) { fclose(merbaseIn); } 

此外,我知道openSourceFile工作(至少对于chr1 ,在设置FILE*的第一个文件句柄时),因为我的应用程序解析chr1行并正确地从FILE*源文件中读取数据。

这个fclose调用导致分段错误发生的原因是什么?

 valgrind --db-attach=yes --leak-check=yes --tool=memcheck --num-callers=16 --leak-resolution=high ./yourprogram args 

segfault很可能是由堆上的内存损坏引起的,而不是任何影响本地的内存。 Valgrind会立即向您显示您所犯的第一个错误访问权限。

编辑:自2014年版本3.10.0以来,不推荐使用valgrind--db-attach选项。发行说明指出:

 The built-in GDB server capabilities are superior and should be used instead. Learn more here: 

http://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.gdbserver

我注意到的一个错误是这一行:

  *chrome = (char *) malloc ((size_t) strlen(field)); 

应该是:

  *chrome = (char *) malloc ((size_t) strlen(field)+1); 

这是因为一个字符串在结尾处有一个结束0,你还必须腾出空间

除了由reinier发现的错误之外 ,我怀疑:

 free(chromosome); 

应该遵循:

 chromosome = NULL; 

以防止潜在使用不再有效的值。

最好的猜测是,代码的其他部分是通过缓冲区溢出或类似错误来破坏内存。

虽然不太可能是原因,但是当完整文件名超过100个字符时,您的文件名数组中可能存在溢出条件。

我建议使用调试器来监视merbaseIn变量使用的内存位置的变化。

通用指针问题

C语言很棒,但它确实要求你不要破坏自己的记忆。 除了前面提到的malloc短1字节的问题,你可能还有其他指针问题。

我建议使用内存调试器 。 在过去, 电围栏相当受欢迎,但这些天我听到更多关于valgrind 。 还有很多其他选择。

为什么这个FILE ** filePtr如果只有这个FILE * filePtr就足够了? 只是一个想法…

具有memcheck valgrind绝对是发现分段错误原因的正确工具。 要将调试器与valgrind ,请注意,自2014年Valgrind 3.10.0发布以来, valgrind--db-attach选项已被弃用。发行说明指出:

 The built-in GDB server capabilities are superior and should be used instead. Learn more here: 

http://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.gdbserver