En esta actividad vamos a ejecutar ficheros que
contienen errores de codificación en Valgrind. Estos ficheros se encuentran bajo el directorio
Valgrind_errors
en vuestro repositorio (con copia local
aquí).
Para cada uno de
los ficheros siguientes, compila con la directiva -g
(gcc -Wall -g tufichero.c -o tuejecutable), ejecútalo con
Valgrind (valgrind --leak-check=yes ./tuejecutable) y
corrige los errores aparecidos, explicando en el mismo fichero (una pequeña
explicación de un par de líneas encerrada entre comentarios) qué error se estaba produciendo.
Fichero strcpy_exercise.c
: copia
una cadena de caracteres en otra.
Fichero printing_exercise.c
: copia
el valor de un entero a un puntero e imprime la dirección de dicho
puntero y su valor recién copiado.
Optionally, subid los ficheros modificados mediante SVN y enséñaselos al profesor para que pueda evaluarlos.
Guía rápida de Valgrind (secciones 1,2,3,4,5 y 6).
Carpeta con nombre Valgrind_first
y fichero testing_valgrind.c
en la carpeta
compartida de Subversion. Tienes una copia local
aquí
Para la detección de fugas de memoria en C vamos a utilizar el framework Valgrind. Este framework tiene un conjunto de herramientas entre las que destaca Memcheck (que será en la que nos centremos), que te permite ejecutar un programa en C y ver si en alguna línea de tu código se puede incurrir en una fuga de memoria o algún otro error, advirtiendo así de posibles problemas en la futura ejecución de tu programa.
Lee la guía rápida de Valgrind que se ofrece como recurso.
Abre un terminal de comandos y compila y ejecuta el
programa testing_valgrind.c
que encontrarás en el
directorio Valgrind_first
de tu carpeta
compartida. Ejecuta de nuevo el programa utilizando Valgrind y analiza
el informe sobre el uso de memoria que imprime.
Modifica el programa
testing_valgrind.c
para que, la ejecución con
Valgrind no muestre error alguno. Súbelo corregido a tu repositorio con
Subversion.
Tipos de errores que detecta la herramienta Memcheck de Valgrind (Sección 4.1. del manual de usuario).
Clasificación de los mensajes de error que imprime Memcheck (Sección 4.2. del manual de usuario).
Vamos a indagar más sobre los posibles errores que detecta Valgrind y, en concreto, con su herramienta Memcheck.
Lee los tipos de errores que Memcheck detecta utilizando el enlace que se ofrece como recurso. Ignora el error denominado “Mismatched use of malloc/new/new [] vs free/delete/delete []”, pues este sólo se produce en programas escritos en C++.
Lee los tipos de mensajes de error que pueden aparecer al ejecutar tu programa con Valgrind, utilizando el segundo enlace que se te da como recurso.
Cuando termines de leer ambos documentos realiza un resumen (1 página por una cara), a modo de tabla, de manera que incluya el tipo de error, una descripción breve (un par de líneas) de por qué aparece ese error, los posibles mensajes que puede sacar Valgrind, y un código de ejemplo asociado. Puedes ver un ejemplo en la siguiente imagen:
Haz el resumen con la hoja orientada en horizontal, para que la tabla se vea mejor. Observa que un mismo tipo de error puede tener varios mensajes asociados, como el de la figura del ejemplo, pero también puede ocurrir que varios tipos de error tengan casi siempre los mismos mensajes (como es el caso de los errores que implican una lectura/escritura inválida). Si no sabes cómo rellenar alguna fila o columna de la tabla, déjala en blanco. Podrás rellenarla a medida que trabajas con Valgrind.
Colección particular de programas escritos hasta ahora en la asignatura que hagan operaciones de gestión dinámica de memoria.
Recorre tu colección de programas escritos en C y la de
tu compañero hasta ahora en el curso y marca aquellos en los que se
incluyen operaciones de gestión dinámica de memoria
(malloc
, calloc
, free
o
realloc
).
Para cada uno de ellos compila y ejecuta de nuevo el programa pero utilizando Valgrind. Sin arreglar ninguna de las anomalías, confecciona una tabla en la que conste esta información para cada programa. Muestra esta tabla al profesor.
Repasa la implementación de cada programa para arreglar las anomalías que se hayan detectado.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #include <stdio.h> int main() { char *p; // Allocation #1 of 19 bytes p = (char *) malloc(13); // Allocation #2 of 12 bytes p = (char *) malloc(11); free(p); // Allocation #3 of 16 bytes p = (char *) malloc(16); return 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ==7279== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. ==7295== Memcheck, a memory error detector ==7295== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. ==7295== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info ==7295== Command: ./a ==7295== ==7295== ==7295== HEAP SUMMARY: ==7295== in use at exit: 29 bytes in 2 blocks ==7295== total heap usage: 3 allocs, 1 frees, 40 bytes allocated ==7295== ==7295== 13 bytes in 1 blocks are definitely lost in loss record 1 of 2 ==7295== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) ==7295== by 0x8048428: main (in /home/gradient/Escritorio/ValgrindErrors/a) ==7295== ==7295== 16 bytes in 1 blocks are definitely lost in loss record 2 of 2 ==7295== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) ==7295== by 0x8048454: main (in /home/gradient/Escritorio/ValgrindErrors/a) ==7295== ==7295== LEAK SUMMARY: ==7295== definitely lost: 29 bytes in 2 blocks ==7295== indirectly lost: 0 bytes in 0 blocks ==7295== possibly lost: 0 bytes in 0 blocks ==7295== still reachable: 0 bytes in 0 blocks ==7295== suppressed: 0 bytes in 0 blocks ==7295== ==7295== For counts of detected and suppressed errors, rerun with: -v ==7295== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0) |
Mira el error error Allocation #1 (13 byte leak) y responde.
Mira el error error Allocation #3 (16 byte leak) y responde.
Observa el siguiente código. ¿Cuál es el error que resultará si compilamos con Valgrind?
1 2 3 4 5 6 | #include <stdio.h> int main() { int x; printf ("x = %d\n", x); } |