Encontrar errores de memoria dinámica con herramientas de detección de errores de memoria
por Parasoft
12 de Julio, 2012
3 min leer
Usar memoria asignada dinámicamente correctamente es un tema delicado. En muchos casos, los programas continúan ejecutándose mucho después de que un error de programación causa graves corrupción de memoria; a veces no se estrellan en absoluto. En esta publicación, veremos cómo el análisis dinámico puede detectar problemas de corrupción de memoria comunes en el código C.
Un error común es intentar reutilizar un puntero después de que ya se haya liberado. Considere las líneas 22-26 del siguiente programa que desasigna bloques de memoria antes de asignar los más grandes:
Punteros colgantes
Si ejecuta este código a través de detección de errores de memoria herramienta como Parasoft Insure ++, obtendrá un mensaje de error sobre un "puntero colgante" en la línea 24. En este caso, el bloque al que apunta string_so_far se libera en la línea 23 y luego se usa en la siguiente línea.
Wikipedia define un puntero colgante como “punteros que no apuntan a un objeto válido del tipo apropiado. Estos son casos especiales de violaciones de seguridad de la memoria. De manera más general, las referencias colgantes y las referencias salvajes son referencias que no se resuelven en un destino válido ". Estos son una clase de errores relacionados con “eliminar un objeto de la memoria explícitamente o destruir el marco de la pila al regresar no altera los punteros asociados. El puntero sigue apuntando a la misma ubicación en la memoria, aunque ahora puede usarse para otros fines " Este es un problema común que a menudo pasa desapercibido porque los programas con estos errores a menudo se compilan sin advertencias y en ocasiones pueden ejecutarse correctamente.
En el ejemplo anterior, la referencia del búfer de memoria por el puntero string_so_far se libera explícitamente y luego se desreferencia. El análisis dinámico detecta estos errores que pueden pasar desapercibidos durante las pruebas e incluso durante el funcionamiento normal de la aplicación hasta que se accede incorrectamente a la memoria incorrecta.
¿Qué otros problemas de memoria dinámica pueden encontrar las herramientas de detección de errores de memoria?
Además de este tipo de problema de memoria dinámica de puntero colgante, detección de errores de memoria herramienta como Parasoft Insure ++ también detecta los siguientes errores:
- Leer o escribir en "punteros colgantes".
- Pasar "punteros colgantes" como argumentos a funciones o devolverlos desde funciones.
- Liberar el mismo bloque de memoria varias veces.
- Intentando liberar memoria asignada estáticamente.
- Liberando memoria de pila (variables locales).
- Pasar un puntero para liberar que no apunta al comienzo de un bloque de memoria.
- Llamadas para liberar con punteros NULL o no inicializados.
- Pasar argumentos sin sentido o argumentos del tipo de datos incorrecto a malloc, calloc, realloc o free.
Análisis en tiempo de compilación
Insure ++ detecta errores tanto en tiempo de compilación como en tiempo de ejecución. Los errores detectados en tiempo de compilación incluyen:
- El elenco del puntero pierde precisión
- Discrepancia en la especificación de formato
- Discrepancia en el tipo de argumento
- El código no se evalúa, no tiene ningún efecto o es inalcanzable
- Identificador indefinido
- Variable declarada, pero nunca utilizada
- Devolviendo el puntero a la variable local
- La función devuelve un valor inconsistente
- Variables no utilizadas
Informes en tiempo de ejecución
Luego, el usuario ejecuta este programa como parte de las pruebas de casos de uso, tal como usaría el programa original, e Insure ++ informa cualquier problema encontrado. Los informes de Insure ++ incluyen información detallada, que incluye: sobre el tipo de error, el archivo fuente y el número de línea, el contenido real de la línea del código fuente, la expresión que causó el problema, con informes que incluyen:
- El tipo de error (por ejemplo, EXPR_UNRELATED_PTRCMP)
- El archivo de origen y el número de línea (por ejemplo, foo.cc:42)
- El contenido real de la línea del código fuente, (por ejemplo, "while (p <g) {")
- La expresión que causó el problema (por ejemplo, "p <g")
- Información sobre todos los punteros y bloques de memoria involucrados en el error:
- Los valores del puntero
- Los bloques de memoria apuntados (si los hay) y cualquier desplazamiento
- La información de asignación de bloques:
- Seguimiento de pila si se asigna dinámicamente.
- Ubicación de la declaración de bloque, (archivo de origen y número de línea), si se asigna en la pila o globalmente.
- Seguimiento de pila de la desasignación del bloque, si corresponde.
- El seguimiento de la pila que muestra cómo llegó el programa a la ubicación del error.
Crédito de la imagen: xithoriano