From: Michael D. Lowis Date: Tue, 12 Aug 2014 13:48:25 +0000 (-0400) Subject: Fix build options for memory leak detector X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=07070126567bf05da096ee0c0ef5e7f5087a178c;p=projs%2Flibcds.git Fix build options for memory leak detector --- diff --git a/Rakefile b/Rakefile index d6888f5..cc18841 100644 --- a/Rakefile +++ b/Rakefile @@ -28,6 +28,7 @@ end TestEnv = Env.clone do |env| env.build_dir('source','build/obj/test_source') env.build_dir('tests','build/obj/tests/source') + env['CFLAGS'] += ['-DLEAK_DETECTION'] env['CPPPATH'] += Dir['tests/'] end diff --git a/source/mem/mem.c b/source/mem/mem.c index cebce06..1debf3a 100644 --- a/source/mem/mem.c +++ b/source/mem/mem.c @@ -1,6 +1,9 @@ #include "mem.h" #include +#if (defined(LEAK_DETECTION) && !defined(NDEBUG)) #include +#include +#endif typedef struct { int refcount; @@ -11,7 +14,11 @@ typedef struct { intptr_t val; } box_t; -#ifndef NDEBUG + +/* If LEAK_DETECTION is turned on then we need to disable the mem_allocate macro + * for the duration of this file. This allows us to use the original + * mem_allocate function without modification in mem_allocate_ld */ +#if (defined(LEAK_DETECTION) && !defined(NDEBUG)) #undef mem_allocate #endif @@ -23,7 +30,7 @@ void* mem_allocate(size_t size, destructor_t p_destruct_fn) return (void*)(p_obj+1); } -#ifndef NDEBUG +#if (defined(LEAK_DETECTION) && !defined(NDEBUG)) typedef struct block_t { void* p_obj; const char* p_file; @@ -32,12 +39,13 @@ typedef struct block_t { } 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; + /* Print out all the live blocks and where they were allocated from */ while (NULL != p_curr) { block_t* to_be_freed = p_curr; @@ -56,13 +64,17 @@ static void print_live_objects(void) { void* mem_allocate_ld(size_t size, destructor_t p_destruct_fn, const char* p_file, int line) { + /* Allocate the object through the ordinary method */ void* p_obj = mem_allocate(size, p_destruct_fn); + /* Create a metadata block for it to track it's usage. */ 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 we haven't already, register an exit handler that will printout the + * unfreed objects before the program quits */ if(!Handler_Registered) { atexit(print_live_objects); @@ -78,7 +90,7 @@ void mem_retain(void* p_obj) p_hdr->refcount += 1; } -#ifndef NDEBUG +#if (defined(LEAK_DETECTION) && !defined(NDEBUG)) static void deregister_block(void* p_obj) { block_t* p_prev = NULL; @@ -114,7 +126,7 @@ void mem_release(void* p_obj) p_hdr->refcount -= 1; if(p_hdr->refcount < 1) { - #ifndef NDEBUG + #if (defined(LEAK_DETECTION) && !defined(NDEBUG)) deregister_block(p_obj); #endif if(p_hdr->p_finalize) diff --git a/source/mem/mem.h b/source/mem/mem.h index 2b9b2e2..7635a90 100644 --- a/source/mem/mem.h +++ b/source/mem/mem.h @@ -17,7 +17,7 @@ extern "C" { /** A function pointer for object destructors */ typedef void (*destructor_t)(void* p_val); -#ifdef NDEBUG +#ifndef LEAK_DETECTION /** * @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.