Как исправить утечку памяти в программе C? - PullRequest
0 голосов
/ 12 апреля 2020

Следующая C программа должна выделить список, а затем освободить его и одновременно распечатать его содержимое:

#include <stdlib.h>
#include <stdio.h>
typedef struct {
struct chain *next;       
int contents;  } chain; 

int main()  {     
    int index;     
    chain *list;     
    chain *p;    
    chain *pointer;     
    list = malloc(sizeof(chain));     
    p = list;     

    for(index=0;index<10;index++) {       
        (*p).contents = index;       
        (*p).next = malloc(sizeof(chain));       
        p = (*p).next; 
       } ;     
    p = pointer = list;     
    index = 0;     

    while (index < 9) { 
        printf("cell # %d: %d\n",index,(*p).contents);       
        p = (*p).next;       
        free(pointer);       
        pointer = p;       
        index++; 
      } ;     
    printf("First cell: %d\n",(*list).contents); 
    return 0;  
  } 

Когда я запускаю Valgrind с полной проверкой утечки, я получаю следующее журнал, который показывает 2 ошибки / утечки памяти:

--13792-- REDIR: 0x401f2f0 (ld-linux-x86-64.so.2:strlen) redirected to 0x580608c1 (???)
--13792-- REDIR: 0x401f0d0 (ld-linux-x86-64.so.2:index) redirected to 0x580608db (???)
--13792-- Reading syms from /usr/lib/valgrind/vgpreload_core-amd64-linux.so
--13792--   Considering /usr/lib/valgrind/vgpreload_core-amd64-linux.so ..
--13792--   .. CRC mismatch (computed 50df1b30 wanted 4800a4cf)
--13792--    object doesn't have a symbol table
--13792-- Reading syms from /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so
--13792--   Considering /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so ..
--13792--   .. CRC mismatch (computed f893b962 wanted 95ee359e)
--13792--    object doesn't have a symbol table
==13792== WARNING: new redirection conflicts with existing -- ignoring it
--13792--     old: 0x0401f2f0 (strlen              ) R-> (0000.0) 0x580608c1 ???
--13792--     new: 0x0401f2f0 (strlen              ) R-> (2007.0) 0x04c32db0 strlen
--13792-- REDIR: 0x401d360 (ld-linux-x86-64.so.2:strcmp) redirected to 0x4c33ee0 (strcmp)
--13792-- REDIR: 0x401f830 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x4c374f0 (mempcpy)
--13792-- Reading syms from /lib/x86_64-linux-gnu/libc-2.27.so
--13792--   Considering /lib/x86_64-linux-gnu/libc-2.27.so ..
--13792--   .. CRC mismatch (computed b1c74187 wanted 042cc048)
--13792--   Considering /usr/lib/debug/lib/x86_64-linux-gnu/libc-2.27.so ..
--13792--   .. CRC is valid
--13792-- REDIR: 0x4edac70 (libc.so.6:memmove) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4ed9d40 (libc.so.6:strncpy) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4edaf50 (libc.so.6:strcasecmp) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4ed9790 (libc.so.6:strcat) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4ed9d70 (libc.so.6:rindex) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4edc7c0 (libc.so.6:rawmemchr) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4edade0 (libc.so.6:mempcpy) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4edac10 (libc.so.6:bcmp) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4ed9d00 (libc.so.6:strncmp) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4ed9800 (libc.so.6:strcmp) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4edad40 (libc.so.6:memset) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4ef80f0 (libc.so.6:wcschr) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4ed9ca0 (libc.so.6:strnlen) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4ed9870 (libc.so.6:strcspn) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4edafa0 (libc.so.6:strncasecmp) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4ed9840 (libc.so.6:strcpy) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4edb0e0 (libc.so.6:memcpy@@GLIBC_2.14) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4ed9da0 (libc.so.6:strpbrk) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4ed97c0 (libc.so.6:index) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4ed9c70 (libc.so.6:strlen) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4ee46c0 (libc.so.6:memrchr) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4edaff0 (libc.so.6:strcasecmp_l) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4edabe0 (libc.so.6:memchr) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4ef8eb0 (libc.so.6:wcslen) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4eda050 (libc.so.6:strspn) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4edaf20 (libc.so.6:stpncpy) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4edaef0 (libc.so.6:stpcpy) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4edc7f0 (libc.so.6:strchrnul) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4edb040 (libc.so.6:strncasecmp_l) redirected to 0x4a2a6e0 (_vgnU_ifunc_wrapper)
--13792-- REDIR: 0x4fca3c0 (libc.so.6:__strrchr_avx2) redirected to 0x4c32730 (rindex)
--13792-- REDIR: 0x4ed3070 (libc.so.6:malloc) redirected to 0x4c2faa0 (malloc)
--13792-- REDIR: 0x4fca1d0 (libc.so.6:__strchrnul_avx2) redirected to 0x4c37020 (strchrnul)
--13792-- REDIR: 0x4fcaab0 (libc.so.6:__mempcpy_avx_unaligned_erms) redirected to 0x4c37130 (mempcpy)
cell # 0: 0
--13792-- REDIR: 0x4ed3950 (libc.so.6:free) redirected to 0x4c30cd0 (free)
cell # 1: 1
cell # 2: 2
cell # 3: 3
cell # 4: 4
cell # 5: 5
cell # 6: 6
cell # 7: 7
cell # 8: 8
cell # 9: 9
==13792== Invalid read of size 4
==13792==    at 0x108797: main (dynmem.c:31)
==13792==  Address 0x522d048 is 8 bytes inside a block of size 16 free'd
==13792==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13792==    by 0x108780: main (dynmem.c:27)
==13792==  Block was alloc'd at
==13792==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13792==    by 0x1086EB: main (dynmem.c:15)
==13792== 
First cell: 0
==13792== 
==13792== HEAP SUMMARY:
==13792==     in use at exit: 16 bytes in 1 blocks
==13792==   total heap usage: 12 allocs, 11 frees, 1,200 bytes allocated
==13792== 
==13792== Searching for pointers to 1 not-freed blocks
==13792== Checked 70,200 bytes
==13792== 
==13792== 16 bytes in 1 blocks are definitely lost in loss record 1 of 1
==13792==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13792==    by 0x108714: main (dynmem.c:19)
==13792== 
==13792== LEAK SUMMARY:
==13792==    definitely lost: 16 bytes in 1 blocks
==13792==    indirectly lost: 0 bytes in 0 blocks
==13792==      possibly lost: 0 bytes in 0 blocks
==13792==    still reachable: 0 bytes in 0 blocks
==13792==         suppressed: 0 bytes in 0 blocks
==13792== 
==13792== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==13792== 
==13792== 1 errors in context 1 of 2:
==13792== Invalid read of size 4
==13792==    at 0x108797: main (dynmem.c:31)
==13792==  Address 0x522d048 is 8 bytes inside a block of size 16 free'd
==13792==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13792==    by 0x108780: main (dynmem.c:27)
==13792==  Block was alloc'd at
==13792==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13792==    by 0x1086EB: main (dynmem.c:15)
==13792== 
==13792== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0) 

Я - полный C новичок и не могу обернуться, откуда берутся эти утечки и что мне нужно сделать, чтобы их исправить. Помощь высоко ценится.

1 Ответ

1 голос
/ 12 апреля 2020

Это объявление

typedef struct {
struct chain *next;       
int contents;  } chain; 

неверно. Там объявлены две структуры. Первая - безымянная структура

typedef struct {

, для которой было назначено имя типа определения chain. И в этой безымянной структуре объявлена ​​еще одна структура struct chain, которая используется в качестве спецификатора элемента данных next.

struct chain *next;       

Таким образом, указатели типов chain * и struct chain * не совместимы.

Структура должна быть объявлена ​​как

typedef struct chain {
    struct chain *next;       
    int contents;  
} chain; 

В этом фрагменте кода

list = malloc(sizeof(chain));     
p = list;     

for(index=0;index<10;index++) {       
    (*p).contents = index;       
    (*p).next = malloc(sizeof(chain));       
    p = (*p).next; 
   } ;  

Вы выделили 11 объектов цепочки типов. Однако в этом фрагменте кода

while (index < 9) { 
    printf("cell # %d: %d\n",index,(*p).contents);       
    p = (*p).next;       
    free(pointer);       
    pointer = p;       
    index++; 
  } ; 

вы освободили только 9 динамически размещенных объектов цепочки типов.

Кроме того, значение списка указателей не изменилось. Таким образом, программа вызывает неопределенное поведение в этом выражении

printf("First cell: %d\n",(*list).contents); 

Программа может быть написана, например, следующим образом.

#include <stdlib.h>
#include <stdio.h>

typedef struct chain
{
    struct chain *next;       
    int contents;  
} chain; 

int main( void )  
{
    const int N = 10;

    chain *list = NULL;

    chain **current = &list;

    for ( int i = 0; i < N; i++ ) 
    {
        *current = malloc( sizeof( chain ) );
        ( *current )->contents = i;       
        ( *current )->next = NULL;       
        current = &( *current )->next;
    } ;     

    for ( int i = 0; i < N - 1; i++ )
    {
        printf( "cell # %d: %d\n", i,  list->contents ); 

        chain *tmp = list;
        list = list->next;
        free( tmp );       
     }

    printf( "First cell: %d\n", list->contents );

    while ( list != NULL )
    {
        chain *tmp = list;
        list = list->next;
        free( tmp );
    }

    return 0;  
} 

Вывод программы:

cell # 0: 0
cell # 1: 1
cell # 2: 2
cell # 3: 3
cell # 4: 4
cell # 5: 5
cell # 6: 6
cell # 7: 7
cell # 8: 8
First cell: 9
...