From d526504719676871376324858fe2073aa2011424 Mon Sep 17 00:00:00 2001 From: Ian Lynagh Date: Mon, 11 Dec 2006 12:49:50 +0000 Subject: [PATCH] When debugging, have the allocator help us a bit 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 | 16 +++++++- rts/RtsUtils.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++- rts/RtsUtils.h | 3 ++ 3 files changed, 126 insertions(+), 4 deletions(-) diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c index 824ef98..5bb9806 100644 --- a/rts/RtsStartup.c +++ b/rts/RtsStartup.c @@ -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 diff --git a/rts/RtsUtils.c b/rts/RtsUtils.c index bf02c32..9f50e3a 100644 --- a/rts/RtsUtils.c +++ b/rts/RtsUtils.c @@ -45,6 +45,96 @@ #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); } diff --git a/rts/RtsUtils.h b/rts/RtsUtils.h index 9313936..cad4216 100644 --- a/rts/RtsUtils.h +++ b/rts/RtsUtils.h @@ -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__); -- 1.7.10.4