When debugging, have the allocator help us a bit
authorIan Lynagh <igloo@earth.li>
Mon, 11 Dec 2006 12:49:50 +0000 (12:49 +0000)
committerIan Lynagh <igloo@earth.li>
Mon, 11 Dec 2006 12:49:50 +0000 (12:49 +0000)
We now check for freeing memory that isn't allocated, and overwrite memory
we are about to free with 0xaa.
It might be nice to also have a flag to control whether the memory
actually gets free'd.

rts/RtsStartup.c
rts/RtsUtils.c
rts/RtsUtils.h

index 824ef98..5bb9806 100644 (file)
@@ -138,7 +138,13 @@ hs_init(int *argc, char **argv[])
        return;
     }
 
-    /* The very first thing we do is grab the start time...just in case we're
+#if defined(DEBUG)
+    /* Start off by initialising the allocator debugging so we can
+     * use it anywhere */
+    initAllocator();
+#endif
+
+    /* Next we do is grab the start time...just in case we're
      * collecting timing statistics.
      */
     stat_startInit();
@@ -470,8 +476,14 @@ hs_exit(void)
     shutdownAsyncIO();
 #endif
 
-    // Finally, free all our storage.
+    // Finally, free all our storage
     freeStorage();
+
+#if defined(DEBUG)
+    /* and shut down the allocator debugging */
+    shutdownAllocator();
+#endif
+
 }
 
 // Compatibility interfaces
index bf02c32..9f50e3a 100644 (file)
 #endif
 
 /* -----------------------------------------------------------------------------
+   Debugging allocator
+   -------------------------------------------------------------------------- */
+
+#if defined(DEBUG)
+
+typedef struct Allocated_ {
+    void *addr;
+    size_t len;
+    struct Allocated_ *next;
+} Allocated;
+
+static Allocated *allocs = NULL;
+
+#ifdef THREADED_RTS
+static Mutex allocator_mutex;
+#endif
+
+void
+initAllocator(void)
+{
+    Allocated *a;
+    size_t alloc_size;
+
+#ifdef THREADED_RTS
+    initMutex(&allocator_mutex);
+#endif
+    alloc_size = sizeof(Allocated);
+    if ((a = (Allocated *) malloc(alloc_size)) == NULL) {
+      /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
+      MallocFailHook((W_) alloc_size, "initialising debugging allocator");
+      stg_exit(EXIT_INTERNAL_ERROR);
+    }
+    a->addr = NULL;
+    a->len = 0;
+    a->next = NULL;
+    allocs = a;
+}
+
+void
+shutdownAllocator(void)
+{
+#ifdef THREADED_RTS
+    closeMutex(&allocator_mutex);
+#endif
+}
+
+static void allocate(void *addr, size_t len) {
+    Allocated *a;
+    size_t alloc_size;
+
+    alloc_size = sizeof(Allocated);
+    if ((a = (Allocated *) malloc(alloc_size)) == NULL) {
+      /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
+      MallocFailHook((W_) alloc_size, "creating info for debugging allocator");
+      stg_exit(EXIT_INTERNAL_ERROR);
+    }
+    a->addr = addr;
+    a->len = len;
+    ACQUIRE_LOCK(&allocator_mutex);
+    a->next = allocs->next;
+    allocs->next = a;
+    RELEASE_LOCK(&allocator_mutex);
+}
+
+static void deallocate(void *addr) {
+    Allocated *prev, *a;
+
+    if (addr == NULL) {
+        barf("Freeing NULL!");
+    }
+
+    ACQUIRE_LOCK(&allocator_mutex);
+    prev = allocs;
+    a = prev->next;
+    while (a != NULL) {
+        if (a->addr == addr) {
+            prev->next = a->next;
+            memset(addr, 0xaa, a->len);
+            free(a);
+            RELEASE_LOCK(&allocator_mutex);
+            return;
+        }
+        prev = a;
+        a = a->next;
+    }
+    barf("Freeing non-allocated memory at %p", addr);
+}
+#endif
+
+/* -----------------------------------------------------------------------------
    Result-checking malloc wrappers.
    -------------------------------------------------------------------------- */
 
@@ -52,12 +142,17 @@ void *
 stgMallocBytes (int n, char *msg)
 {
     char *space;
+    size_t n2;
 
-    if ((space = (char *) malloc((size_t) n)) == NULL) {
+    n2 = (size_t) n;
+    if ((space = (char *) malloc(n2)) == NULL) {
       /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
       MallocFailHook((W_) n, msg); /*msg*/
       stg_exit(EXIT_INTERNAL_ERROR);
     }
+#if defined(DEBUG)
+    allocate(space, n2);
+#endif
     return space;
 }
 
@@ -65,12 +160,18 @@ void *
 stgReallocBytes (void *p, int n, char *msg)
 {
     char *space;
+    size_t n2;
 
-    if ((space = (char *) realloc(p, (size_t) n)) == NULL) {
+    n2 = (size_t) n;
+    if ((space = (char *) realloc(p, (size_t) n2)) == NULL) {
       /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
       MallocFailHook((W_) n, msg); /*msg*/
       stg_exit(EXIT_INTERNAL_ERROR);
     }
+#if defined(DEBUG)
+    deallocate(p);
+    allocate(space, n2);
+#endif
     return space;
 }
 
@@ -84,6 +185,9 @@ stgCallocBytes (int n, int m, char *msg)
       MallocFailHook((W_) n*m, msg); /*msg*/
       stg_exit(EXIT_INTERNAL_ERROR);
     }
+#if defined(DEBUG)
+    allocate(space, (size_t) n * (size_t) m);
+#endif
     return space;
 }
 
@@ -93,6 +197,9 @@ stgCallocBytes (int n, int m, char *msg)
 void
 stgFree(void* p)
 {
+#if defined(DEBUG)
+  deallocate(p);
+#endif
   free(p);
 }
 
index 9313936..cad4216 100644 (file)
@@ -13,6 +13,9 @@
  * (Checked) dynamic allocation
  * -------------------------------------------------------------------------- */
 
+extern void initAllocator(void);
+extern void shutdownAllocator(void);
+
 extern void *stgMallocBytes(int n, char *msg)
     GNUC3_ATTRIBUTE(__malloc__);