From 11d035577814211fdfc8ab091a28a02ad2c913cb Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Sun, 14 Sep 2003 04:23:49 +0000 Subject: [PATCH] Se termina el malloc debugger, incluyendo un test simple (falta documentar). --- Makefile | 12 +++- dllist.h | 1 - documentacion.h | 6 ++ memdebug.c | 136 ++++++++++++++++++++++++++++++++++++++++++++ memdebug.h | 49 ++++++++++++++++ memdebug_debugger.h | 48 ++++++++++++++++ memdebug_test.c | 55 ++++++++++++++++++ meminfo.c | 45 +++++++++++++++ meminfo.h | 41 ++++++++----- 9 files changed, 374 insertions(+), 19 deletions(-) create mode 100644 memdebug.c create mode 100644 memdebug.h create mode 100644 memdebug_debugger.h create mode 100644 memdebug_test.c create mode 100644 meminfo.c diff --git a/Makefile b/Makefile index f5a610a..afa2713 100644 --- a/Makefile +++ b/Makefile @@ -14,20 +14,26 @@ # # Opciones para el compilador. -CFLAGS=-ansi -pedantic -Wall -g3 +CFLAGS=-ansi -pedantic -Wall -g3 -DDEBUG +CC=gcc-3.2 +# Pruebas. +TESTS=dllist_test memdebug_test # Programa a compilar. -TARGETS= +TARGETS=$(TESTS) # Regla por defecto. all: tp1 # Pruebas. -tests: dllist_test +tests: $(TESTS) ./dllist_test + ./memdebug_test dllist_test: dllist.o +memdebug_test: dllist.o meminfo.o memdebug.o + tp1: $(TARGETS) # Regla para borrar. diff --git a/dllist.h b/dllist.h index ad88060..10edb6c 100644 --- a/dllist.h +++ b/dllist.h @@ -17,7 +17,6 @@ #ifndef DLLIST_H #define DLLIST_H - /** Tipo de dato booleano. */ typedef enum { FALSE, /**< Falso. */ diff --git a/documentacion.h b/documentacion.h index 353654a..190ad2a 100644 --- a/documentacion.h +++ b/documentacion.h @@ -150,4 +150,10 @@ b = b * 2 Puede suponerse que estas ecuaciones son válidas. +\section conclusiones Conclusiones. + +Problemas: + - "Sobrecarga" de malloc. Lo hacía antes de un #include y me + tiraba un error porque la definicion de la stdlib me expandía el macro. + - */ diff --git a/memdebug.c b/memdebug.c new file mode 100644 index 0000000..bb91640 --- /dev/null +++ b/memdebug.c @@ -0,0 +1,136 @@ +/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=0 fo+=t tw=80: + * + * Taller de Programación (75.42). + * + * Ejercicio Número 2: + * Programa calculadora. + * + * Copyleft 2003 - Leandro Lucarella + * Puede copiar, modificar y distribuir este programa bajo los términos de + * la licencia GPL (http://www.gnu.org/). + * + * Creado: sáb ago 30 20:08:45 ART 2003 + * + * $Id$ + */ + +#include "memdebug.h" +#include "dllist.h" +#include "meminfo.h" +#include +#include +#include + +/** + * Lista interna a utilizar en memdebug_malloc() y memdebug_free(). + */ +static DLList* memdebug_list; + +/** + * FIXME la búsqueda se realiza de atrás hacia adelante para que sea más + * eficiente, ya que generalmente se borra primero la memoria que se pidió + * úitima. + */ +bool memdebug_DLList_find(DLList* list, void* ptr) { + MemInfo* i; + for (i = DLList_end(list); DLList_have_more(list); i = DLList_prev(list)) { + if (i->pointer == ptr) { + return TRUE; + } + } + return FALSE; +} + +void memdebug_info_print(MemInfo* mi, FILE* fp) { + char fecha[30]; + struct tm* ltime; + ltime = localtime(&(mi->time)); + strftime(fecha, 30, "%c", ltime); + fprintf(fp, "0x%08X | %5u | %-25s | %-16s | %5u\n", + (size_t)(mi->pointer), + mi->bytes, + fecha, + mi->filename, + mi->fileline); +} + +void memdebug_list_print(FILE* fp) { + MemInfo* mi; + fprintf(fp, "%-10s | %-5s | %-25s | %-16s | %-5s\n", + "Ptr", + "Bytes", + "Fecha", + "Archivo", + "Línea"); + fprintf(fp, "-----------+-------+---------------------------+" + "------------------+------\n"); + for (mi = DLList_begin(memdebug_list); + DLList_have_more(memdebug_list); + mi = DLList_next(memdebug_list)) { + memdebug_info_print(mi, fp); + } +} + +void* memdebug_malloc(size_t bytes, const char* fname, size_t fline) { + void* ptr; + /* Si no está creada la lista global, la creo (o intento). */ + if (!memdebug_list) { + memdebug_list = DLList_new(); + /* Si no se puede crear la lista no reservo memoria, devuelvo NULL. */ + if (!memdebug_list) { +#ifdef DEBUG + fprintf(stderr, "%s: No se pudo crear la lista interna " + "(llamado desde %s, línea %i).\n", + __FILE__, fname, fline); +#endif + return NULL; + } + } + /* Intento reservar memoria pedida. */ + ptr = malloc(bytes); + /* Si se puedo reservar, creo un nuevo nodo y lo agrego a la lista. */ + if (ptr) { + MemInfo* mi = MemInfo_new(ptr, bytes, fname, fline); + /* Si no se puede crear el nodo, devuelvo NULL. */ + if (!mi || !DLList_push(memdebug_list, mi)) { +#ifdef DEBUG + fprintf(stderr, "%s: No se pudo crear el nodo para 0x%X " + "(llamado desde %s, línea %u).\n", + __FILE__, (size_t)ptr, fname, fline); +#endif + return NULL; + } + } + return ptr; +} + +void memdebug_free(void* ptr) { + /* Busca en la lista y de encontrarlo nos lo deja en el elemento actual. */ + if (memdebug_DLList_find(memdebug_list, ptr)) { + /* Lo encontró, elimino el nodo actual. */ + DLList_remove_current(memdebug_list); +#ifdef DEBUG + } else { + fprintf(stderr, "%s: No se encontro el ptr 0x%X en la lista.\n", + __FILE__, (size_t)ptr); +#endif + } + /* Lo encuentre o no, trata de liberar la memoria. */ + free(ptr); +} + +void memdebug_end(void) { + /* Si hay una lista. */ + if (memdebug_list) { + MemInfo* mi; + /* Imprimo la lista. */ + memdebug_list_print(stderr); + /* Libero la memoria de cada elemento y cada puntero almacenado. */ + while (!DLList_empty(memdebug_list)) { + mi = DLList_pop(memdebug_list); + free(mi->pointer); + MemInfo_delete(mi); + } + } +} + diff --git a/memdebug.h b/memdebug.h new file mode 100644 index 0000000..33bf638 --- /dev/null +++ b/memdebug.h @@ -0,0 +1,49 @@ +/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=1 fo+=t tw=80: + * + * Taller de Programación (75.42). + * + * Ejercicio Número 2: + * Programa calculadora. + * + * Copyleft 2003 - Leandro Lucarella + * Puede copiar, modificar y distribuir este programa bajo los términos de + * la licencia GPL (http://www.gnu.org/). + * + * Creado: sáb ago 30 20:08:45 ART 2003 + * + * $Id$ + */ + +#ifndef MEMDEBUG_H +#define MEMDEBUG_H + +#include "dllist.h" +#include "meminfo.h" +/* Para usar FILE. */ +#include + +/** + * @todo FIXME + */ +void* memdebug_malloc(size_t bytes, const char* fname, size_t fline); + +/** + * @todo FIXME + */ +void memdebug_free(void* ptr); + +/** + * Imprime una DLList en un archivo. + * + * \param list DLList a imprimir. + * \param fh Puntero al archivo a escribir. + */ +void memdebug_list_print(FILE* fp); + +/** + * @todo FIXME + * Imprime la lista de memoria no liberada, la libera y borra la lista interna. + */ +void memdebug_end(void); + +#endif /* MEMDEBUG_H */ diff --git a/memdebug_debugger.h b/memdebug_debugger.h new file mode 100644 index 0000000..3150261 --- /dev/null +++ b/memdebug_debugger.h @@ -0,0 +1,48 @@ +/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=1 fo+=t tw=80: + * + * Taller de Programación (75.42). + * + * Ejercicio Número 2: + * Programa calculadora. + * + * Copyleft 2003 - Leandro Lucarella + * Puede copiar, modificar y distribuir este programa bajo los términos de + * la licencia GPL (http://www.gnu.org/). + * + * Creado: sáb ago 30 20:08:45 ART 2003 + * + * $Id$ + */ + +/** \file + * + * Este es el archivo a incluir si se quieren usar las funciones personalizadas + * de malloc() y free(). + */ + +#ifndef MEMDEBUG_DEBUGGER_H +#define MEMDEBUG_DEBUGGER_H + +#include "memdebug.h" + +#ifdef malloc +#undef malloc +#endif + +#ifdef free +#undef free +#endif + +/** + * Malloc personalizado. + * \see memdebug_malloc() + */ +#define malloc(b) memdebug_malloc(b, __FILE__, __LINE__) + +/** + * Free personalizado. + * \see memdebug_free() + */ +#define free(p) memdebug_free(p) + +#endif /* MEMDEBUG_DEBUGGER_H */ diff --git a/memdebug_test.c b/memdebug_test.c new file mode 100644 index 0000000..b11e471 --- /dev/null +++ b/memdebug_test.c @@ -0,0 +1,55 @@ +/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=0 fo+=t: + * + * Taller de Programación (75.42). + * + * Ejercicio Número 2: + * Programa calculadora. + * + * Copyleft 2003 - Leandro Lucarella + * Puede copiar, modificar y distribuir este programa bajo los términos de + * la licencia GPL (http://www.gnu.org/). + * + * Creado: sáb ago 30 18:24:31 ART 2003 + * + * $Id$ + */ + +/** \file + * + * Hace chequeos para probar el memdebugger. + */ + +/* Para utilizar printf() */ +#include +/* Para utilizar EXIT_SUCCES */ +#include +/* Para utilizar assert() */ +#include + +/* Para llamar al malloc() y free() personalizados. */ +#include "memdebug_debugger.h" + +/** + * Programa para probar el memdebug. + * + * \return EXIT_SUCCESS o código de error devuelto por abort() si hubo un + * error. + */ +int main(void) { + /* Declaración de variables. */ + void* ptr1 = malloc(1000); + void* ptr2 = malloc(1000); + void* ptr3 = malloc(1000); + + memdebug_list_print(stderr); + + fprintf(stderr, "\n"); + + free(ptr1); + free(ptr2); + free(ptr3); + + memdebug_end(); + + return EXIT_SUCCESS; +} diff --git a/meminfo.c b/meminfo.c new file mode 100644 index 0000000..f0214f0 --- /dev/null +++ b/meminfo.c @@ -0,0 +1,45 @@ +/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=0 fo+=t tw=80: + * + * Taller de Programación (75.42). + * + * Ejercicio Número 2: + * Programa calculadora. + * + * Copyleft 2003 - Leandro Lucarella + * Puede copiar, modificar y distribuir este programa bajo los términos de + * la licencia GPL (http://www.gnu.org/). + * + * Creado: sáb ago 30 20:08:45 ART 2003 + * + * $Id$ + */ + +#include "meminfo.h" +#include +#include + +MemInfo* MemInfo_new(void* ptr, size_t bytes, const char* fname, size_t fline) { + /* Aloco memoria. */ + MemInfo* mi = malloc(sizeof(MemInfo)); + /* Si la obtuve, inicializo con los datos y la hora actual. */ + if (mi) { + mi->pointer = ptr; + mi->bytes = bytes; + mi->time = time(NULL); + mi->fileline = fline; + /* Reservo memoria para hacer la copia del nombre del archivo. */ + mi->filename = (char*)malloc(strlen(fname)); + /* Copio el nombre del archivo. */ + strcpy(mi->filename, fname); + } + /* Devuelvo el nuevo puntero. */ + return mi; +} + +void MemInfo_delete(MemInfo* mi) { + /* Libero primero la memoria del nombre del archivo. */ + free(mi->filename); + /* Libero la memoria del MemInfo. */ + free(mi); +} + diff --git a/meminfo.h b/meminfo.h index d013f92..f152d9f 100644 --- a/meminfo.h +++ b/meminfo.h @@ -17,30 +17,41 @@ #ifndef MEMINFO_H #define MEMINFO_H +#include + /** - * Nodo de la lista. + * Información sobre la memoria. */ typedef struct { + /** Puntero a la memoria reservada. */ void* pointer; + /** Cantidad de bytes reservados. */ size_t bytes; + /** Fecha en la que se reservó. */ time_t time; + /** Nombre del archivo de donde se reservó. */ char* filename; + /** Línea en la que se reservó. */ size_t fileline; } MemInfo; -MemInfo* MemInfo_new(void* ptr, size_t bytes, char* fname, size_t fline) { - /* Aloco memoria. */ - MemInfo* mi = (MemInfo*)malloc(sizeof(MemInfo)); - /* Si la obtuve, inicializo con los datos y la hora actual. */ - if (mi) { - mi->pointer = ptr; - mi->bytes = bytes; - mi->time = time(); - mi->filename = fname; - mi->fileline = fline; - } - /* Devuelvo el nuevo puntero. */ - return mi; -} +/** + * Crea un nuevo MemInfo. + * + * \param ptr Puntero a un área de memoria. + * \param bytes Cantidad de bytes reservados. + * \param fname Nombre del archivo de donde se reservó. + * \param fline Línea en donde se reservó. + * + * \return Puntero al nuevo MemInfo o NULL si no hay espacio en la memoria. + */ +MemInfo* MemInfo_new(void* ptr, size_t bytes, const char* fname, size_t fline); + +/** + * Elimina un MemInfo. + * + * \param mi MemInfo a eliminar. + */ +void MemInfo_delete(MemInfo* mi); #endif /* MEMINFO_H */ -- 2.43.0