Ladění dynamicky alokované paměti v jazyce C
Ladění dynamicky alokované paměti v jazyce C je poměrně jednoduché, pokud se použijí specializované nástroje, které ho výrazně usnadňují.
Valgrind
Nástroj Valgrind[1] je určen pro ladění a profilování programů v unixových systémech (Linux a podobně). Obsahuje více interních nástrojů, které slouží k různým účelům. Pro hledání chyb při práci s dynamicky alokovanou pamětí slouží nástroj Memcheck.
Zápis do nerezervované paměti
Následující příklad pokus.c
demonstruje chybu 'označovanou jako +−1 při alokaci paměti pro řetězec. Často se zapomíná, že řetězec je ukončen znakem \x0 (binárně nula) a pro něj se musí také rezervovat místo (jinak může přepsat data, která jsou uložena bezprostředně za použitou proměnnou):
#include <string.h>
#include <stdlib.h>
int main()
{
char *adresa = malloc(4);
strcpy(adresa,"Ahoj");
free(adresa);
return 0;
}
Program přeložíme (přičemž překladač neohlásí žádnou chybu) a spustíme pomocí nástroje Valgrind:
gcc -Wall -o pokus pokus.c valgrind ./pokus
Nástroj Valgrind vypíše níže uvedený text:
==12695== Memcheck, a memory error detector. ==12695== Copyright (C) 2002-2006, and GNU GPL'd, by Julian Seward et al. ==12695== Using LibVEX rev 1658, a library for dynamic binary translation. ==12695== Copyright (C) 2004-2006, and GNU GPL'd, by OpenWorks LLP. ==12695== Using valgrind-3.2.1, a dynamic binary instrumentation framework. ==12695== Copyright (C) 2000-2006, and GNU GPL'd, by Julian Seward et al. ==12695== For more details, rerun with: -v ==12695== ==12695== Invalid write of size 1 ==12695== at 0x4004F8: main (pokus.c:8) ==12695== Address 0x4C5C034 is 0 bytes after a block of size 4 alloc'd ==12695== at 0x4A05809: malloc (vg_replace_malloc.c:149) ==12695== by 0x4004E9: main (pokus.c:7) ==12695== ==12695== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 1) ==12695== malloc/free: in use at exit: 0 bytes in 0 blocks. ==12695== malloc/free: 1 allocs, 1 frees, 4 bytes allocated. ==12695== For counts of detected errors, rerun with: -v ==12695== All heap blocks were freed -- no leaks are possible.
Po úvodních zprávách ohledně licence je oznámen zápis, který o 1 bajt (size 1) přesahuje 4 alokované bajty (4 alloc'd).
Memory leak
Únik paměti je situace, kdy program zapomene ukazatel na alokovanou paměť. Níže uvedený program v druhé alokaci přepíše proměnnou, ve které byl uložen ukazatel na první alokaci. Paměť z první alokace je tak pro použití v programu ztracena. K jejímu uvolnění dojde až po skončení programu:
#include <string.h>
#include <stdlib.h>
int main()
{
char *adresa = malloc(5);
strcpy(adresa,"Ahoj");
adresa = malloc(10);
free(adresa);
return 0;
}
Program přeložíme a při použití Valgrindu uvedeme parametr --leak-check=full
, který problém úniku paměti odhalí:
gcc -Wall -o pokus pokus.c valgrind --leak-check=full ./pokus
Ve výpisu nástroje Valgrind nalezneme:
==12868== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 1) ==12868== malloc/free: in use at exit: 5 bytes in 1 blocks. ==12868== malloc/free: 2 allocs, 1 frees, 15 bytes allocated. ==12868== For counts of detected errors, rerun with: -v ==12868== searching for pointers to 1 not-freed blocks. ==12868== checked 63,688 bytes. ==12868== ==12868== 5 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==12868== at 0x4A05809: malloc (vg_replace_malloc.c:149) ==12868== by 0x4004E9: main (pokus.c:6) ==12868== ==12868== LEAK SUMMARY: ==12868== definitely lost: 5 bytes in 1 blocks. ==12868== possibly lost: 0 bytes in 0 blocks. ==12868== still reachable: 0 bytes in 0 blocks. ==12868== suppressed: 0 bytes in 0 blocks. ==12868== Reachable blocks (those to which a pointer was found) are not shown. ==12868== To see them, rerun with: --show-reachable=yesVe výpisu je oznámena ztráta odkazu na první alokovaný úsek paměti na řádku číslo 6.