From a1d2d05ddc38c091e4dc9ff750c0d141995e46dc Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 5 Mar 2010 11:04:40 +0100 Subject: Add memdebug module, a simple malloc debugger --- memdebug/memdebug.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++ memdebug/memdebug.h | 44 ++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 memdebug/memdebug.c create mode 100644 memdebug/memdebug.h (limited to 'memdebug') diff --git a/memdebug/memdebug.c b/memdebug/memdebug.c new file mode 100644 index 0000000..9725cb1 --- /dev/null +++ b/memdebug/memdebug.c @@ -0,0 +1,113 @@ +#include +#include + +/* define/undef to enable tracing of errors */ +#define MEMDEBUG_TRACE +/* define/undef to enable tracing of double free errors */ +#define MEMDEBUG_TRACE_DOUBLE_FREE + +#include "memdebug.h" + +static struct memdebug_heap_item *heap_head = NULL; +static struct memdebug_heap_item *heap_tail = NULL; + +void *__memdebug_malloc(size_t size, const char *func, + const char *file, const unsigned int line) +{ + void *ret; + struct memdebug_heap_item *hi = malloc(sizeof(struct memdebug_heap_item)); + + if (!hi) + goto out_err; + + ret = malloc(size); + if (!ret) { + free(hi); + goto out_err; + } + + hi->next = NULL; + hi->addr = ret; + hi->size = size; + hi->func = func; + hi->file = file; + hi->line = line; +#ifdef MEMDEBUG_TRACE_DOUBLE_FREE + hi->freed_func = NULL; + hi->freed_file = NULL; + hi->line = 0; +#endif + + if (!heap_head) + heap_head = hi; + if (!heap_tail) + heap_tail = hi; + else { + heap_tail->next = hi; + heap_tail = hi; + } + + return ret; + +out_err: + memdebug_trace("malloc failed (%s:%d:%s)", file, line, func); + return NULL; +} + +void __memdebug_free(void *ptr, const char *func, + const char *file, const unsigned int line) +{ + struct memdebug_heap_item *hi, *prev; + + if (!ptr) { + memdebug_trace("trying to free NULL pointer (%s:%d:%s)", file, line, func); + return; + } + + for (hi = heap_head, prev = NULL; hi; prev = hi, hi = hi->next) + if (hi->addr ==ptr) + break; + + if (!hi) { + memdebug_trace("no memory allocated at %p (%s:%d:%s)", ptr, file, line, func); + return; + } + +#ifdef MEMDEBUG_TRACE_DOUBLE_FREE + if (hi->freed_func) { + memdebug_trace("double free at %p (%s:%d:%s)\nalready freed by %s:%d:%s", + ptr, file, line, func, hi->freed_file, hi->freed_line, hi->freed_func); + return; + } + + hi->freed_func = func; + hi->freed_file = file; + hi->freed_line = line; +#else + /* Delete the item from the linked list */ + if (prev) + prev->next = hi->next; + else + heap_head = hi->next; + if (heap_tail == hi) + heap_tail = prev; + + free(hi); +#endif + + free(ptr); +} + +void memdebug_report(void) +{ + struct memdebug_heap_item *hi; + size_t total_size = 0; + + fprintf(stderr, "\n\n*** Reporting allocated memory ***\n"); + for (hi = heap_head; hi; hi = hi->next) { + fprintf(stderr, " %zu bytes at %p (%s:%d:%s)\n", hi->size, hi->addr, hi->file, hi->line, hi->func); + total_size += hi->size; + } + fprintf(stderr, "Total size: %zu bytes\n\n", total_size); + fflush(stderr); +} diff --git a/memdebug/memdebug.h b/memdebug/memdebug.h new file mode 100644 index 0000000..d96e356 --- /dev/null +++ b/memdebug/memdebug.h @@ -0,0 +1,44 @@ +#ifndef _MEMDEBUG_H_ +#define _MEMDEBUG_H_ + +#include + +#ifdef MEMDEBUG_TRACE +# define memdebug_trace(fmt, args...) \ + ({ \ + fprintf(stderr, "\n\n*** " fmt " ***\n\n", ##args); \ + fflush(stderr); \ + }) +#else +# define memdebug_trace(fmt, args...) +#endif + +struct memdebug_heap_item { + struct memdebug_heap_item *next; + + void *addr; + size_t size; + + const char *func; + const char *file; + unsigned int line; + +#ifdef MEMDEBUG_TRACE_DOUBLE_FREE + const char *freed_func; + const char *freed_file; + unsigned int freed_line; +#endif +}; + +#define memdebug_malloc(size) \ + __memdebug_malloc(size, __func__, __FILE__, __LINE__) +#define memdebug_free(ptr) \ + __memdebug_free(ptr, __func__, __FILE__, __LINE__) + +void *__memdebug_malloc(size_t size, const char *func, + const char *file, const unsigned int line); +void __memdebug_free(void *ptr, const char *func, + const char *file, const unsigned int line); +void memdebug_report(void); + +#endif /* _MEMDEBUG_H_ */ -- cgit v1.2.3-54-g00ecf From 9a0f4b01e9ccdd0733a31dd09b045624eda75c5f Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 5 Mar 2010 11:07:04 +0100 Subject: memdebug: Add file header --- memdebug/memdebug.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'memdebug') diff --git a/memdebug/memdebug.c b/memdebug/memdebug.c index 9725cb1..50a46fc 100644 --- a/memdebug/memdebug.c +++ b/memdebug/memdebug.c @@ -1,3 +1,12 @@ +/* + * memdebug - A simple malloc/free debugger + * + * This can essentially be useful on embedded systems platforms where tools such + * as valgrind are not available. + * + * Copyright (c) 2010, Tobias Klauser + */ + #include #include -- cgit v1.2.3-54-g00ecf From dbd23d3a6263ad4c79915757b903835ab5ab28d0 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 5 Mar 2010 11:20:33 +0100 Subject: No double \n --- memdebug/memdebug.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'memdebug') diff --git a/memdebug/memdebug.h b/memdebug/memdebug.h index d96e356..3ae1159 100644 --- a/memdebug/memdebug.h +++ b/memdebug/memdebug.h @@ -6,7 +6,7 @@ #ifdef MEMDEBUG_TRACE # define memdebug_trace(fmt, args...) \ ({ \ - fprintf(stderr, "\n\n*** " fmt " ***\n\n", ##args); \ + fprintf(stderr, "*** " fmt " ***\n", ##args); \ fflush(stderr); \ }) #else -- cgit v1.2.3-54-g00ecf From 0a2822d4ad8721673e31d122549e9426105b0289 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 8 Mar 2010 23:08:41 +0100 Subject: memdebug rework --- memdebug/memdebug.c | 67 +++++++++++++++++++++++++++++++---------------------- memdebug/memdebug.h | 4 +--- 2 files changed, 40 insertions(+), 31 deletions(-) (limited to 'memdebug') diff --git a/memdebug/memdebug.c b/memdebug/memdebug.c index 50a46fc..84a2c86 100644 --- a/memdebug/memdebug.c +++ b/memdebug/memdebug.c @@ -12,14 +12,31 @@ /* define/undef to enable tracing of errors */ #define MEMDEBUG_TRACE -/* define/undef to enable tracing of double free errors */ -#define MEMDEBUG_TRACE_DOUBLE_FREE #include "memdebug.h" static struct memdebug_heap_item *heap_head = NULL; static struct memdebug_heap_item *heap_tail = NULL; +void memdebug_start(void) +{ + /* Empty for now */ +} + +void memdebug_cleanup(void) +{ + struct memdebug_heap_item *hi; + + for (hi = heap_head; hi; hi = hi->next) { + if (hi->addr) + free(hi->addr); + free(hi); + } + + heap_head = NULL; + heap_tail = NULL; +} + void *__memdebug_malloc(size_t size, const char *func, const char *file, const unsigned int line) { @@ -41,20 +58,15 @@ void *__memdebug_malloc(size_t size, const char *func, hi->func = func; hi->file = file; hi->line = line; -#ifdef MEMDEBUG_TRACE_DOUBLE_FREE hi->freed_func = NULL; hi->freed_file = NULL; hi->line = 0; -#endif if (!heap_head) heap_head = hi; - if (!heap_tail) - heap_tail = hi; - else { + if (heap_tail) heap_tail->next = hi; - heap_tail = hi; - } + heap_tail = hi; return ret; @@ -74,7 +86,7 @@ void __memdebug_free(void *ptr, const char *func, } for (hi = heap_head, prev = NULL; hi; prev = hi, hi = hi->next) - if (hi->addr ==ptr) + if (hi->addr == ptr) break; if (!hi) { @@ -82,7 +94,6 @@ void __memdebug_free(void *ptr, const char *func, return; } -#ifdef MEMDEBUG_TRACE_DOUBLE_FREE if (hi->freed_func) { memdebug_trace("double free at %p (%s:%d:%s)\nalready freed by %s:%d:%s", ptr, file, line, func, hi->freed_file, hi->freed_line, hi->freed_func); @@ -92,31 +103,31 @@ void __memdebug_free(void *ptr, const char *func, hi->freed_func = func; hi->freed_file = file; hi->freed_line = line; -#else - /* Delete the item from the linked list */ - if (prev) - prev->next = hi->next; - else - heap_head = hi->next; - if (heap_tail == hi) - heap_tail = prev; - - free(hi); -#endif - - free(ptr); + + /* Free the memory but keep the memdebug information */ + free(hi->addr); + hi->addr = NULL; } -void memdebug_report(void) +void memdebug_report(int report_all) { struct memdebug_heap_item *hi; size_t total_size = 0; + size_t still_allocated = 0; - fprintf(stderr, "\n\n*** Reporting allocated memory ***\n"); + fprintf(stderr, "\n\n*** Reporting allocated/freed memory ***\n"); for (hi = heap_head; hi; hi = hi->next) { - fprintf(stderr, " %zu bytes at %p (%s:%d:%s)\n", hi->size, hi->addr, hi->file, hi->line, hi->func); + if (hi->addr) { + fprintf(stderr, " IN USE %zu bytes at %p (%s:%d:%s)\n", + hi->size, hi->addr, hi->file, hi->line, hi->func); + still_allocated += hi->size; + } else if (report_all) { + fprintf(stderr, " FREE %zu bytes at %p (%s:%d:%s)\n", + hi->size, hi->addr, hi->file, hi->line, hi->func); + } total_size += hi->size; } - fprintf(stderr, "Total size: %zu bytes\n\n", total_size); + fprintf(stderr, "Total size: %zu bytes, %zu bytes still allocated\n\n", + total_size, still_allocated); fflush(stderr); } diff --git a/memdebug/memdebug.h b/memdebug/memdebug.h index 3ae1159..7a816c0 100644 --- a/memdebug/memdebug.h +++ b/memdebug/memdebug.h @@ -23,11 +23,9 @@ struct memdebug_heap_item { const char *file; unsigned int line; -#ifdef MEMDEBUG_TRACE_DOUBLE_FREE const char *freed_func; const char *freed_file; unsigned int freed_line; -#endif }; #define memdebug_malloc(size) \ @@ -39,6 +37,6 @@ void *__memdebug_malloc(size_t size, const char *func, const char *file, const unsigned int line); void __memdebug_free(void *ptr, const char *func, const char *file, const unsigned int line); -void memdebug_report(void); +void memdebug_report(int report_all); #endif /* _MEMDEBUG_H_ */ -- cgit v1.2.3-54-g00ecf