fclose()导致分段错误

3
我有一个制表符分隔的文本文件需要解析,它的第一列包含格式为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);                                                                                                                                                         
    }                                                                                                                                                                             
}      

问题在于我的应用程序在从第一个染色体(从chr1)到第二个染色体(到chr2)时出现分段错误,出现在以下代码行,我在其中关闭了第一个染色体文件:

fclose(merbaseIn);

我知道我没有向fclose传递NULL指针,因为在出现分段错误之前,我正在从这个文件中读取数据。我甚至可以将其包装在条件语句中,但仍然会出现错误:

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

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

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

8个回答

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

很可能导致段错误的原因是堆上的内存损坏,而不是影响本地变量的任何内容。Valgrind将立即显示您所做的第一个错误访问。Valgrind
编辑:自2014年发布3.10.0版本以来,--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


1
我没有在双指针内运行 free。我也没有在其他地方释放指针。我放弃了这个应用程序,从头开始编写,并在进行编写时运行 valgrind 以确保我正确地管理内存。感谢您向我介绍这个工具! - Alex Reynolds
是的,valgrind 教会了我:1)每个人都是对的,我应该只使用智能(auto/refcount 等)指针或垃圾回收;2)有了 valgrind,我实际上不需要垃圾回收。唯一的注意事项是测试覆盖率。我认为使用 valgrind 比我熟悉的任何 GC 语言的工具(例如 JVM 或 .NET 语言)更容易找到内存泄漏。 - Jonathan Graehl

5

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

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

应该是:

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

这是因为字符串末尾有一个闭合的0,你也需要为其腾出空间。

2
没错,但是strlen()返回的是size_t类型,所以不需要强制转换。而malloc()返回的是void*类型,在C语言中可以转换为任何其他(数据)指针类型,因此也不需要强制转换。 - unwind
在这种情况下,您可以使用strdup()来替换malloc()+strcpy()。 - user172818
3
我不同意使用(char*)强制转换,因为这明确表示了意图。 - Toad

1

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

free(chromosome);

应该跟随:

chromosome = NULL;

为了防止使用不再有效的值的可能性。

1

最好的猜测是你代码的其它部分通过缓冲区溢出或类似漏洞来破坏内存。

尽管不太可能成为原因,但当完整文件名超过100个字符时,您的文件名数组存在潜在的溢出条件。

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


1

通用指针问题

C语言是一种很好的语言,但它要求您不要破坏自己的内存。除了之前提到的malloc少分配1个字节的问题外,您可能还会遇到其他指针问题。

我建议使用内存调试器。过去,Electric Fence非常流行,但现在我更多地听到valgrind。还有很多其他选择。


0

0

检查您使用"malloc"的每个位置,看看是否犯了错误。

例如,我将从文件中读取的行放入char **中,但我错误地使用了malloc:

my_list = malloc(sizeof(char) * num_lines_found_in_file);

本应该是:

my_list = malloc(sizeof(char*)* num_lines_found_in_file);

0
为什么需要 FILE** filePtr,如果只有 FILE* filePtr 就足够了呢? 只是一种想法...

使用双重文件指针在关闭文件时是一个好的实践。这样做可以在关闭文件后将原始文件指针设置为NULL,因为它不是函数参数。 - H_squared

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接