Search code examples
cpointersmallocvalgrindfree

Why am I losing `3,744,768 bytes` of memory?


I'm kind of new to programming and I was writing a program to recover JPEG files present in "card.raw" by comparing the 4 continuous bytes. If they demarcated a JPEG the program had to copy a block of 512 bytes into a new file saved a xxx.jpg (000.jpg, 001.jpg, etc). If after the block had been copied, the start of a new JPEG was found, the current file would be closed and the next file would be opened to copy the next JPG. Else the next block would be copied in the same file.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int counter = 0;
    if(argc != 2)
    {
        printf("Usage: ./recover image\n");
        return 1;
    }
    typedef uint8_t BYTE;
    FILE *recover = fopen(argv[1], "r");
    if(recover == NULL)
    {
        printf("ERRNO 1 IS %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }
    fseek(recover, 0L, SEEK_END);
    unsigned long size = ftell(recover);
    fseek(recover, 0L, SEEK_SET);
    BYTE *CHUNK = (BYTE*)malloc(size * sizeof(BYTE));
    fread(CHUNK, sizeof(BYTE), size, recover);      //Break recover into bytes
    int j = 0;
    char file[8] = "xxx.jpg";
    FILE *f = NULL;
    int s = 0;
    while(j  < size)
    {
        if(CHUNK[j] == 0xff && CHUNK[j + 1] == 0xd8 && CHUNK[j + 2] == 0xff)                           //Check if byte is JPEG format 1st byte
        {
                            if(s == 0)
                            {
                                if(f != NULL)
                                {
                                    f = NULL;
                                }
                                sprintf(file ,"%03d.jpg",counter);  //Create custom file of format xxx.jpg
                                f = fopen(file,"w");
                                if(f == NULL)
                                {
                                    printf("ERRNO 2 is %s\n", strerror(errno));
                                    exit(EXIT_FAILURE);
                                }
                                fwrite(&CHUNK[j], 512, sizeof(BYTE), f);  //Copy 512 bytes from start of JPEG file as 512 bytes form one 'block`
                                j += 512; //Increment to check initial bytes of next 'block'
                                s++;
                            }
                            else
                            {
                                fclose(f);
                                counter++;
                                s = 0;
                            }
        }
        else if(s > 0)   //Else continue searching
        {
            fwrite(&CHUNK[j], 512, sizeof(BYTE), f);
            j += 512;
        }
        else j += 512;
    }
    fclose(f);
    fclose(recover);
    free(&CHUNK);
    return 0;
}

The program worked perfectly except for the fact the Valgrind gives me the following report:

==1560== Memcheck, a memory error detector
==1560== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==1560== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==1560== Command: ./recover card.raw
==1560== 
==1560== Invalid free() / delete / delete[] / realloc()
==1560==    at 0x4C32D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1560==    by 0x400BF4: main (recover.c:69)
==1560==  Address 0x1fff000510 is on thread 1's stack
==1560==  in frame #1, created by main (recover.c:9)
==1560== 
==1560== 
==1560== HEAP SUMMARY:
==1560==     in use at exit: 3,744,768 bytes in 1 blocks
==1560==   total heap usage: 103 allocs, 103 frees, 3,981,816 bytes allocated
==1560== 
==1560== 3,744,768 bytes in 1 blocks are definitely lost in loss record 1 of 1
==1560==    at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1560==    by 0x4009FA: main (recover.c:26)
==1560== 
==1560== LEAK SUMMARY:
==1560==    definitely lost: 3,744,768 bytes in 1 blocks
==1560==    indirectly lost: 0 bytes in 0 blocks
==1560==      possibly lost: 0 bytes in 0 blocks
==1560==    still reachable: 0 bytes in 0 blocks
==1560==         suppressed: 0 bytes in 0 blocks
==1560== 
==1560== For counts of detected and suppressed errors, rerun with: -v
==1560== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

Valgrind seems to say that the problem is with the memory allocation in line 26:

BYTE *CHUNK = (BYTE*)malloc(size * sizeof(BYTE));

But I have freed the allocated memory with free(&CHUNK); at the end. I'd like to know why Valgrind reports that 3,744,768 bytes in 1 blocks have been definitely lost.


Solution

  • free(&CHUNK) is asking to free the space for the variable CHUNK, i.e. the (e.g. 4 or 8) bytes that the pointer itself take; besides not freeing the memory you are thinking of, this is undefined behavior, as you can free only memory that was allocated by malloc and friends, and I'm surprised you don't get a crash due to some sanity check inside the allocator.

    What you actually need to do is to free the memory pointed-by CHUNK, so you have to do free(CHUNK).