c fopen() 在打开许多文件时给我分段错误
c fopen() gives me segmentation fault when opening many files
我必须编写代码来进行外部归并排序。
这部分是第 1 阶段,它写入 {num_blocos} 个文件,其中包含 400KB 的排序文件:
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 x 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 试图打开6 MB 或更多的文件“file10run1.bin”,有人可以给我灯吗?
您在同一 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);
}
我必须编写代码来进行外部归并排序。 这部分是第 1 阶段,它写入 {num_blocos} 个文件,其中包含 400KB 的排序文件:
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 x 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 试图打开6 MB 或更多的文件“file10run1.bin”,有人可以给我灯吗?
您在同一 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);
}