jueves, febrero 02, 2012

Algunas notas rápidas de valgrind (I)

Una de las mejoras herramientas que he usado en estos últimos tiempos para la programación en C es valgrind, un conjunto de herramientas
que nos permite instrumentalizar nuestros binarios para analizar el comportamientos de éstos. Fundamentalmente lo uso para analizar consumo de memoria y posibles memory leaks
que tengan los programas. Aparte da información de accesos erróneos de memoria.

La herramienta de instrumentación más sencilla que usa es el detector de memory leaks. Para ello suelo ejecutar el programa de la siguiente manera:

valgrind --log-file=leak --leak-check=full --dsymutil=yes ./binario argumento1 argumento2 ...
Esta es la manera más sencilla de generar un informe, en este caso usando la herramienta de instrumentación por defecto, que en este caso es memcheck y
es la encargada de detectar los problemas de memoria (leaks, escritura fuera de bloques reservados, saltos tomados a partir de valores de variables que
no han sido inicialidados), y se le dice a dicha utilidad, con --leak-check=full que memcheck utilice información detallada de la gestión de memoria.

El resto de las opciones indica el fichero donde queremos que se almacene la información, --log-file=fichero, y la opción --dsymutil=yes es una opción específica
de MacOS X para que utilice la utilidad dsymutil para tener
la información de depuración almacenada en el binario.

Para que valgrind nos pueda tener los números de líneas del programa, hay que compilarlo con información de depuración (por ejemplo la opción del gcc para que esto ocurra es -g)


#include <stdio.h>
#include <stdlib.h>
int func1(void)
{
        char *p = NULL;
        p = malloc (1000);
}
int func2 (void)
{
        int asco;
        if (asco)
        {
                printf ("Uno\n");
        }
        else
        {
                printf ("Dos\n");
        }
}
int main (int argc,char **argv)
{
        func1 ();
        func2 ();
        exit (0);
}

Por ejemplo el código anterior tiene un memory leak y una comparación tomada en función de una variable que no ha sido inicialidada. Si compilamos este
programa con la opción -g y ejecutamos el valgrind:

gcc -g -o binario test1.c

valgrind --log-file=leak --leak-check=full --dsymutil=yes ./binario

En el fichero leak nos generará la siguiente salida:

==16246== Memcheck, a memory error detector
==16246== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==16246== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==16246== Command: ./a.out
==16246== Parent PID: 16092
==16246==
==16246== Conditional jump or move depends on uninitialised value(s)
==16246==    at 0x100000E5E: func2 (test1.c:11)
==16246==    by 0x100000EB0: main (test1.c:23)
==16246==
==16246==
==16246== HEAP SUMMARY:
==16246==     in use at exit: 7,087 bytes in 34 blocks
==16246==   total heap usage: 34 allocs, 0 frees, 7,087 bytes allocated
==16246==
==16246== 1,000 bytes in 1 blocks are definitely lost in loss record 9 of 10
==16246==    at 0xB823: malloc (vg_replace_malloc.c:266)
==16246==    by 0x100000E41: func1 (test1.c:6)
==16246==    by 0x100000EAB: main (test1.c:22)
==16246==
==16246== LEAK SUMMARY:
==16246==    definitely lost: 1,000 bytes in 1 blocks
==16246==    indirectly lost: 0 bytes in 0 blocks
==16246==      possibly lost: 0 bytes in 0 blocks
==16246==    still reachable: 6,087 bytes in 33 blocks
==16246==         suppressed: 0 bytes in 0 blocks
==16246== Reachable blocks (those to which a pointer was found) are not shown.
==16246== To see them, rerun with: --leak-check=full --show-reachable=yes
==16246==
==16246== For counts of detected and suppressed errors, rerun with: -v
==16246== Use --track-origins=yes to see where uninitialised values come from
==16246== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 1 from 1)

Podemos ver los dos errores el memory leak de no liberal el malloc y el salto tomado en base a una variable que no esta inicialida.

Referencias


Technorati Tags:

No hay comentarios: