]> git.mdlowis.com Git - projs/libcds.git/commitdiff
Update mem module to count allocations and deletions for a lightweight form of leak...
authorMichael D. Lowis <mike@mdlowis.com>
Wed, 20 Aug 2014 02:36:23 +0000 (22:36 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Wed, 20 Aug 2014 02:36:23 +0000 (22:36 -0400)
Rakefile
source/mem/mem.c
source/mem/mem.h
tests/test_list.c

index cc188418897000be1c399ccc95e7ae93613b35fb..bd197ea368d51785669cc6519dca131f49521585 100644 (file)
--- a/Rakefile
+++ b/Rakefile
@@ -19,7 +19,7 @@ task(:posix){ is_windows = false }
 
 # Define the compiler environment
 Env = Rscons::Environment.new do |env|
-  env.build_dir('source/','build/obj/source')
+  env.build_dir('source','build/obj/source')
   env["CFLAGS"] += ['-Wall', '-Wextra', '-Werror']
   env['CPPPATH'] += Dir['source/**/']
 end
@@ -28,7 +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['CFLAGS']  += ['-DLEAK_DETECT_LEVEL=1']
   env['CPPPATH'] += Dir['tests/']
 end
 
index 51a85f9495d7981caf4b125283168aeb2be0a6f1..81b9b2d2317b90e59690e899a00dcd5f63ea27eb 100644 (file)
@@ -1,6 +1,6 @@
 #include "mem.h"
 #include <stdlib.h>
-#ifdef LEAK_DETECTION
+#ifdef LEAK_DETECT_LEVEL
 #include <stdbool.h>
 #include <stdio.h>
 #endif
@@ -14,22 +14,18 @@ typedef struct {
     intptr_t val;
 } box_t;
 
-/* If LEAK_DETECTION is turned on then we need to disable the mem_allocate macro
+/* 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 */
-#ifdef LEAK_DETECTION
+#if (LEAK_DETECT_LEVEL == 2)
 #undef mem_allocate
+void* mem_allocate(size_t size, destructor_t p_destruct_fn);
 #endif
 
-void* mem_allocate(size_t size, destructor_t p_destruct_fn)
-{
-    obj_t* p_obj = (obj_t*)malloc(sizeof(obj_t) + size);
-    p_obj->refcount = 1;
-    p_obj->p_finalize = p_destruct_fn;
-    return (void*)(p_obj+1);
-}
+#if (LEAK_DETECT_LEVEL > 0)
+bool Handler_Registered = false;
 
-#ifdef LEAK_DETECTION
+#if (LEAK_DETECT_LEVEL == 2)
 typedef struct block_t {
     void* p_obj;
     const char* p_file;
@@ -38,10 +34,12 @@ typedef struct block_t {
 } block_t;
 
 block_t* Live_Blocks = NULL;
+#elif (LEAK_DETECT_LEVEL == 1)
+size_t Num_Allocations = 0;
+#endif
 
-bool Handler_Registered = false;
-
-static void print_live_objects(void) {
+static void summarize_leaks(void) {
+    #if (LEAK_DETECT_LEVEL == 2)
     bool leak_detected = false;
     block_t* p_curr = Live_Blocks;
     /* Print out all the live blocks and where they were allocated from */
@@ -59,8 +57,15 @@ static void print_live_objects(void) {
     }
     if(leak_detected)
         puts("Memory leak(s) detected!");
+    #elif (LEAK_DETECT_LEVEL == 1)
+    if(Num_Allocations > 0) {
+        puts("Warning: Memory leak(s) detected!");
+        printf("\nFor more details set the LEAK_DETECT_LEVEL build option to 2 or run the executable in valgrind.\n");
+    }
+    #endif
 }
 
+#if (LEAK_DETECT_LEVEL == 2)
 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 */
@@ -76,21 +81,15 @@ void* mem_allocate_ld(size_t size, destructor_t p_destruct_fn, const char* p_fil
      * unfreed objects before the program quits */
     if(!Handler_Registered)
     {
-        atexit(print_live_objects);
+        atexit(summarize_leaks);
         Handler_Registered = true;
     }
     return p_obj;
 }
 #endif
+#endif
 
-void* mem_retain(void* p_obj)
-{
-    obj_t* p_hdr = (((obj_t*)p_obj)-1);
-    p_hdr->refcount += 1;
-    return p_obj;
-}
-
-#ifdef LEAK_DETECTION
+#if (LEAK_DETECT_LEVEL == 2)
 static void deregister_block(void* p_obj)
 {
     block_t* p_prev = NULL;
@@ -120,21 +119,22 @@ static void deregister_block(void* p_obj)
 }
 #endif
 
-void mem_release(void* p_obj)
+void* mem_allocate(size_t size, destructor_t p_destruct_fn)
 {
-    obj_t* p_hdr = (((obj_t*)p_obj)-1);
-    p_hdr->refcount -= 1;
-    if(p_hdr->refcount < 1)
+    obj_t* p_obj = (obj_t*)malloc(sizeof(obj_t) + size);
+    p_obj->refcount = 1;
+    p_obj->p_finalize = p_destruct_fn;
+    #if (LEAK_DETECT_LEVEL == 1)
+    Num_Allocations++;
+    /* If we haven't already, register an exit handler that will printout the
+     * unfreed objects before the program quits */
+    if(!Handler_Registered)
     {
-        #ifdef LEAK_DETECTION
-        deregister_block(p_obj);
-        #endif
-        if(p_hdr->p_finalize)
-        {
-            p_hdr->p_finalize(p_obj);
-        }
-        free(p_hdr);
+        atexit(summarize_leaks);
+        Handler_Registered = true;
     }
+    #endif
+    return (void*)(p_obj+1);
 }
 
 int mem_num_references(void* p_obj)
@@ -143,13 +143,28 @@ int mem_num_references(void* p_obj)
     return p_hdr->refcount;
 }
 
-void mem_autorelease(void* p_obj)
+void* mem_retain(void* p_obj)
 {
-    (void)p_obj;
+    obj_t* p_hdr = (((obj_t*)p_obj)-1);
+    p_hdr->refcount += 1;
+    return p_obj;
 }
 
-void mem_releaseall(void)
+void mem_release(void* p_obj)
 {
+    obj_t* p_hdr = (((obj_t*)p_obj)-1);
+    p_hdr->refcount -= 1;
+    if(p_hdr->refcount < 1)
+    {
+        #if (LEAK_DETECT_LEVEL == 2)
+        deregister_block(p_obj);
+        #endif
+        if(p_hdr->p_finalize)
+        {
+            p_hdr->p_finalize(p_obj);
+        }
+        free(p_hdr);
+    }
 }
 
 void* mem_box(intptr_t val)
index 5b2cafd2f7c09640ef7cdd8f41a06729dbda2cfc..b621e4ea3904e93210d5f340eb77e556a3795b05 100644 (file)
@@ -17,12 +17,12 @@ extern "C" {
 /** A function pointer for object destructors */
 typedef void (*destructor_t)(void* p_val);
 
-/* If debug is disabled, disable leak detection as well */
-#ifdef NDEBUG
-#undef LEAK_DETECTION
+/** Unless otherwise specified, no leak detection will occur */
+#ifndef LEAK_DETECT_LEVEL
+#define LEAK_DETECT_LEVEL 0
 #endif
 
-#ifndef LEAK_DETECTION
+#if (LEAK_DETECT_LEVEL < 2)
 /**
  * @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.
@@ -63,19 +63,6 @@ void* mem_retain(void* p_obj);
  */
 void mem_release(void* p_obj);
 
-/**
- * @brief Schedules an object to be released at a later time when more convenient.
- *
- * @param p_obj The object to be released.
- */
-void mem_autorelease(void* p_obj);
-
-/**
- * @brief Release all objects scheduled to be released reclaiming their memory
- *        if necessary.
- */
-void mem_releaseall(void);
-
 /**
  * @brief Create a reference counted box holding the given value so that it can
  *        be placed in a container.
index 59652235d27635a4d6508d56f7d7123c3ee96ffb..cd61a72439430fb4b43469a940ae01ddb573be6d 100644 (file)
@@ -20,7 +20,6 @@ TEST_SUITE(List) {
         CHECK( NULL != list );
         CHECK( NULL == list->head );
         CHECK( NULL == list->tail );
-        mem_release( list );
     }
 
     //-------------------------------------------------------------------------