0

i have to write a code to make an external merge sort. This part is phase 1 where it writes {num_blocos} files with 400KB sorted files:

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;
    }
}

and this is phase 2 where it merge all files {n by n} each run or rewrite it to the next run.

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);
}

My problem comes here:

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);
}

When my original file has 1MB it works well, but when it has 99MB that is the size i want or even 6MB, it gives me segmentation fault, following debug i found it was when the tempb fopen tries to open the file "file10run1.bin" in 6 or more MB, someone could give me a light?

  • `sprintf(file_write, "file%drun%d.bin", k, n);` looks suspicious when `file_write` is of size 20. As soon as `k` and `n` have more than 8 digits between them, you overflow your buffer. – Nate Eldredge Jul 19 '20 at 19:54
  • i tried with 25, but wasn't the problem, following the debug the maximum size of it was 18. – endrew rafael Jul 19 '20 at 19:56
  • I think you need to create a [mcve]. – Nate Eldredge Jul 19 '20 at 20:15
  • i put all my code in a gist, don't know if it will be enough since all the functions except the mergeFileSort works well. https://gist.github.com/ERTHang/39d70b485229ef90cb6b3a8ed336fb09 – endrew rafael Jul 19 '20 at 20:29

1 Answers1

1

You are using fclose on the same temp file handle more than once.

Running your test program with Address Sanitizer yields:

=================================================================
==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

The following patch fixes this issue, but there are two memory leaks remaining elsewhere (left as a trivial exercise for you to fix, use gcc -fsanitize=address to find it):

--- 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);
     }
Employed Russian
  • 199,314
  • 34
  • 295
  • 362