From 7666165919a4494048cce8330cc550c5a06c2ec6 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Mon, 11 Aug 2014 22:23:10 -0400 Subject: [PATCH] leak detector implementation --- source/mem/mem.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ source/mem/mem.h | 7 ++++ 2 files changed, 94 insertions(+) diff --git a/source/mem/mem.c b/source/mem/mem.c index c2eb7e6..0d92d31 100644 --- a/source/mem/mem.c +++ b/source/mem/mem.c @@ -1,5 +1,6 @@ #include "mem.h" #include +#include typedef struct { int refcount; @@ -10,6 +11,10 @@ typedef struct { intptr_t val; } box_t; +#ifndef NDEBUG +#undef mem_allocate +#endif + void* mem_allocate(size_t size, destructor_t p_destruct_fn) { obj_t* p_obj = (obj_t*)malloc(sizeof(obj_t) + size); @@ -18,18 +23,100 @@ void* mem_allocate(size_t size, destructor_t p_destruct_fn) return (void*)(p_obj+1); } +#ifndef NDEBUG +typedef struct block_t { + void* p_obj; + const char* p_file; + int line; + struct block_t* p_next; +} block_t; + +block_t* Live_Blocks = NULL; +bool Handler_Registered = false; + +#include +static void print_live_objects(void) { + bool leak_detected = false; + block_t* p_curr = Live_Blocks; + while (NULL != p_curr) + { + block_t* to_be_freed = p_curr; + printf("%#x %s (line %d): %d references to object\n", + (unsigned int)p_curr->p_obj, + p_curr->p_file, + p_curr->line, + mem_num_references(p_curr->p_obj)); + p_curr = p_curr->p_next; + free(to_be_freed); + leak_detected = true; + } + if(leak_detected) + puts("Memory leak(s) detected!"); +} + +void* mem_allocate_ld(size_t size, destructor_t p_destruct_fn, const char* p_file, int line) +{ + void* p_obj = mem_allocate(size, p_destruct_fn); + block_t* p_block = (block_t*)malloc(sizeof(block_t)); + p_block->p_obj = p_obj; + p_block->p_file = p_file; + p_block->line = line; + p_block->p_next = Live_Blocks; + Live_Blocks = p_block; + if(!Handler_Registered) + { + atexit(print_live_objects); + Handler_Registered = true; + } + return p_obj; +} +#endif + void mem_retain(void* p_obj) { obj_t* p_hdr = (((obj_t*)p_obj)-1); p_hdr->refcount += 1; } +#ifndef NDEBUG +static void deregister_block(void* p_obj) +{ + block_t* p_prev = NULL; + block_t* p_curr = Live_Blocks; + while((NULL != p_curr) && (NULL != p_curr->p_next)) + { + if (p_obj == p_curr->p_obj) + { + block_t* p_doomed = p_curr; + if(p_prev == NULL) + { + Live_Blocks = p_curr->p_next; + } + else + { + p_prev->p_next = p_curr->p_next; + } + free(p_doomed); + break; + } + else + { + p_prev = p_curr; + p_curr = p_curr->p_next; + } + } +} +#endif + void mem_release(void* p_obj) { obj_t* p_hdr = (((obj_t*)p_obj)-1); p_hdr->refcount -= 1; if(p_hdr->refcount < 1) { + #ifndef NDEBUG + deregister_block(p_obj); + #endif if(p_hdr->p_finalize) { p_hdr->p_finalize(p_obj); diff --git a/source/mem/mem.h b/source/mem/mem.h index 80534ab..2b9b2e2 100644 --- a/source/mem/mem.h +++ b/source/mem/mem.h @@ -17,6 +17,7 @@ extern "C" { /** A function pointer for object destructors */ typedef void (*destructor_t)(void* p_val); +#ifdef NDEBUG /** * @brief Allocates a new reference counted object of the given size which will * be destructed with the given function before it's memory is reclaimed. @@ -27,6 +28,12 @@ typedef void (*destructor_t)(void* p_val); * @return Pointer to the newly allocated object */ void* mem_allocate(size_t size, destructor_t p_destruct_fn); +#else +#define mem_allocate(size,destructor) \ + mem_allocate_ld(size, destructor, __FILE__, __LINE__) + +void* mem_allocate_ld(size_t size, destructor_t p_destruct_fn, const char* p_file, int line); +#endif /** * @brief Returns the reference count for the given object. -- 2.55.0