【问题标题】:c fopen() gives me segmentation fault when opening many filesc fopen() 在打开许多文件时给我分段错误
【发布时间】:2020-11-09 02:03:03
【问题描述】:

我必须编写代码来进行外部合并排序。 这部分是第 1 阶段,它使用 400KB 排序文件写入 {num_blocos} 个文件:

char file_name[20];
while (1)
{
    size_read = fread(bloco, tam, mem_bloco, file);
    if (size_read != 0)
    {
        heapSort(bloco, size_read);
        sprintf(file_name, "file%drun0.bin", num_blocos);
        temp = fopen(file_name, "wb");
        fwrite(bloco, tam, size_read, temp);
        num_blocos++;
        fclose(temp);
    }
    else
    {
        break;
    }
}

这是第 2 阶段,它在每次运行时合并所有文件 {n by n} 或将其重写到下一次运行。

int k = 0, n = 1, j = 0;;
char file_write[20], file_read[20];

while (n < num_blocos)
{
    while (k<num_blocos)
    {
        sprintf(file_write, "file%drun%d.bin", k, n);
        file = fopen(file_write, "wb");
        if (k + 1 == num_blocos)
        {
            sprintf(file_read, "file%drun%d.bin", k, j);
            temp = fopen(file_read, "rb");
            int size = fread(bloco, tam, mem_bloco, temp);
            fwrite(bloco, tam, size, file);
            break;
        }
        else
        {
            mergeSortFile(k, k + n, file, j);
            sprintf(file_name, "file%drun%d.bin", k, j);
            remove(file_name);
            sprintf(file_name, "file%drun%d.bin", k+n, j);
            remove(file_name);
            k += 2 * n;
        }
    }
    k = 0;
    j = n;
    n *= 2;
    fclose(temp);
    fclose(file);
    remove(file_read);
}

我的问题来了:

FILE *tempa, *tempb;
char file_name[20];
sprintf(file_name, "file%drun%d.bin", posb1, j);
tempa = fopen(file_name, "wb+");
if( tempa == NULL ) {
    fprintf(stderr, "Couldn't open %s: %s\n", file_name, strerror(errno));
    exit(1);
}
sprintf(file_name, "file%drun%d.bin", posb2, j);
tempb = fopen(file_name, "wb+");
if( tempb == NULL ) {
    fprintf(stderr, "Couldn't open %s: %s\n", file_name, strerror(errno));
    exit(1);
}

当我的原始文件有 1MB 时它工作得很好,但是当它有 99MB 是我想要的大小甚至 6MB 时,它给了我分段错误,调试后我发现它是当 tempb fopen 尝试打开文件时“ file10run1.bin" 在 6 MB 或更多 MB,有人可以给我一个灯吗?

【问题讨论】:

  • file_write 的大小为20 时,sprintf(file_write, "file%drun%d.bin", k, n); 看起来很可疑。一旦kn 之间的位数超过8 位,就会溢出缓冲区。
  • 我尝试使用 25,但不是问题,调试后它的最大大小为 18。
  • 我认为你需要创建一个minimal reproducible example
  • 我把我所有的代码都放在了一个要点中,不知道这是否足够,因为除了 mergeFileSort 之外的所有函数都运行良好。 gist.github.com/ERTHang/39d70b485229ef90cb6b3a8ed336fb09

标签: c file segmentation-fault fopen mergesort


【解决方案1】:

您在同一个temp 文件句柄上多次使用fclose

使用 Address Sanitizer 运行测试程序会产生:

=================================================================
==3720049==ERROR: AddressSanitizer: attempting double-free on 0x615000002100 in thread T0:
    #0 0x7f51a7ee4277 in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x107277)
    #1 0x7f51a7c8dd5f in _IO_deallocate_file /build/glibc-M65Gwz/glibc-2.30/libio/libioP.h:863
    #2 0x7f51a7c8dd5f in _IO_new_fclose /build/glibc-M65Gwz/glibc-2.30/libio/iofclose.c:74
    #3 0x7f51a7ee2490 in __interceptor_fclose (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x105490)
    #4 0x5615b5ab1805 in fileSort /tmp/so/extsort.c:106
    #5 0x5615b5ab131c in main /tmp/so/extsort.c:27
    #6 0x7f51a7c40e0a in __libc_start_main ../csu/libc-start.c:308
    #7 0x5615b5ab1249 in _start (/tmp/so/a.out+0x1249)

0x615000002100 is located 0 bytes inside of 488-byte region [0x615000002100,0x6150000022e8)
freed by thread T0 here:
    #0 0x7f51a7ee4277 in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x107277)
    #1 0x7f51a7c8dd5f in _IO_deallocate_file /build/glibc-M65Gwz/glibc-2.30/libio/libioP.h:863
    #2 0x7f51a7c8dd5f in _IO_new_fclose /build/glibc-M65Gwz/glibc-2.30/libio/iofclose.c:74

previously allocated by thread T0 here:
    #0 0x7f51a7ee4628 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x107628)
    #1 0x7f51a7c8e62a in __fopen_internal /build/glibc-M65Gwz/glibc-2.30/libio/iofopen.c:65
    #2 0x6e69622e306e74  (<unknown module>)

SUMMARY: AddressSanitizer: double-free (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x107277) in __interceptor_free
==3720049==ABORTING

以下补丁修复了此问题,但其他地方仍有两个内存泄漏(留作小练习供您修复,使用gcc -fsanitize=address 查找):

--- extsort.c   2020-07-19 17:42:02.354991453 -0700
+++ extsort-fixed.c     2020-07-19 17:41:57.067008342 -0700
@@ -64,6 +64,7 @@
             fwrite(bloco, size, size_read, temp);
             num_blocos++;
             fclose(temp);
+            temp = NULL;
         }
         else
         {
@@ -103,7 +104,10 @@
         k = 0;
         j = n;
         n *= 2;
-        fclose(temp);
+        if (temp != NULL)
+          fclose(temp);
+        temp = NULL;
+
         fclose(file);
         remove(file_read);
     }

【讨论】:

  • 非常感谢,它成功了,fsanitize 非常完美,发现了另外两个漏洞,ty :D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-13
  • 1970-01-01
  • 2019-05-11
  • 2015-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多