Ladění dynamicky alokované paměti v jazyce C: Porovnání verzí

Z Milan Kerslager
Přejít na: navigace, hledání
(Založení článku)
 
m (Memory leak: fix)
 
Řádka 49: Řádka 49:
 
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'').
 
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 ===
Ú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:
+
Únik paměti (anglicky ''memory leak'') 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:
  
 
<source lang=c>
 
<source lang=c>

Aktuální verze z 6. 4. 2010, 11:03

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).

Únik paměti

Únik paměti (anglicky memory leak) 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=yes
Ve výpisu je oznámena ztráta odkazu na první alokovaný úsek paměti na řádku číslo 6.
  1. http://cs.wikipedia.org/wiki/Valgrind