Почему я теряю `3,744,768 байт` памяти?

#c #pointers #malloc #valgrind #free

#c #указатели #маллок #валгринд #Бесплатно

Вопрос:

Я новичок в программировании, и я писал программу для восстановления файлов JPEG, присутствующих в «card.raw», путем сравнения 4 непрерывных байтов. Если они разграничили JPEG, программе пришлось скопировать блок из 512 байт в новый файл, сохраненный xxx.jpg (000.jpg , 001.jpg , и т.д.). Если после копирования блока было найдено начало нового JPEG, текущий файл будет закрыт, а следующий файл будет открыт для копирования следующего JPG. Иначе следующий блок будет скопирован в тот же файл.

 #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 imagen");
        return 1;
    }
    typedef uint8_t BYTE;
    FILE *recover = fopen(argv[1], "r");
    if(recover == NULL)
    {
        printf("ERRNO 1 IS %sn", 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 amp;amp; CHUNK[j   1] == 0xd8 amp;amp; CHUNK[j   2] == 0xff)                           //Check if byte is JPEG format 1st byte
        {
                            if(s == 0)
                            {
                                if(f != NULL)
                                {
                                    f = NULL;
                                }
                                sprintf(file ,"d.jpg",counter);  //Create custom file of format xxx.jpg
                                f = fopen(file,"w");
                                if(f == NULL)
                                {
                                    printf("ERRNO 2 is %sn", strerror(errno));
                                    exit(EXIT_FAILURE);
                                }
                                fwrite(amp;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(amp;CHUNK[j], 512, sizeof(BYTE), f);
            j  = 512;
        }
        else j  = 512;
    }
    fclose(f);
    fclose(recover);
    free(amp;CHUNK);
    return 0;
}
 

Программа работала отлично, за исключением того факта Valgrind , что она выдает мне следующий отчет:

 ==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 кажется, говорят, что проблема связана с выделением памяти в line 26 :

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

Но я освободил выделенную память с free(amp;CHUNK); помощью в конце. Я хотел бы знать, почему Valgrind появились такие сообщения 3,744,768 bytes in 1 blocks definitely lost .

Комментарии:

1. Не имеет отношения к вашей проблеме: есть ли какая-то конкретная причина, по которой вы читаете весь файл в памяти? Поскольку вы обрабатываете его поблочно, вам нужно только читать / обрабатывать 512 байт за раз, в этом нет malloc необходимости

Ответ №1:

free(amp;CHUNK) запрашивает free пространство для переменной CHUNK , то есть (например, 4 или 8) байт, которые занимает сам указатель; помимо того, что вы не освобождаете память, о которой вы думаете, это неопределенное поведение, поскольку вы можете free использовать только память, которая была выделена malloc and friends , и я удивлен, что вы не получаете сбой из-за некоторой проверки работоспособности внутри распределителя.

Что вам на самом деле нужно сделать, так это освободить указанную память CHUNK , так что вы должны это сделать free(CHUNK) .

Комментарии:

1. Дополнительным доказательством является то, что valgrind сообщает Invalid free() в строке 69 и отмечает Address 0x1fff000510 is on thread 1's stack .

2. @FredLarson thread 1's stack Ссылается ли здесь на стек, к которому обращается программа main ?

3. @MelPradeep да, это первый (и единственный) поток вашего приложения.