From 1be293629833a43a5ecf3a76c6ed838d183a2683 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 30 May 2013 14:27:24 +0000 Subject: [PATCH] Backtrace for unfreed memory blocks Added an option to show backtrace from where non-freed datablock was allocated from. To enable this feature, simply enable DEBUG_BACKTRACE in mallocn.c file and all unfreed datablocks will be followed up by a backtrace. Currently works on linux and osx only, windows support is on TODO. This feature is for sure disabled by default, so does not affect any builds which don't explicitly define DEBUG_BACKTRACE. --- intern/guardedalloc/intern/mallocn.c | 66 +++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/intern/guardedalloc/intern/mallocn.c b/intern/guardedalloc/intern/mallocn.c index 65d3c11bc23..48738acc22a 100644 --- a/intern/guardedalloc/intern/mallocn.c +++ b/intern/guardedalloc/intern/mallocn.c @@ -87,6 +87,17 @@ */ //#define DEBUG_THREADS +/* Only for debugging: + * Defining DEBUG_BACKTRACE will store a backtrace from where + * memory block was allocated and print this trace for all + * unfreed blocks. + */ +#define DEBUG_BACKTRACE + +#ifdef DEBUG_BACKTRACE +# define BACKTRACE_SIZE 100 +#endif + #ifdef DEBUG_MEMCOUNTER /* set this to the value that isn't being freed */ # define DEBUG_MEMCOUNTER_ERROR_VAL 0 @@ -127,6 +138,11 @@ typedef struct MemHead { #ifdef DEBUG_MEMDUPLINAME int need_free_name, pad; #endif + +#ifdef DEBUG_BACKTRACE + void *backtrace[BACKTRACE_SIZE]; + int backtrace_size; +#endif } MemHead; /* for openmp threading asserts, saves time troubleshooting @@ -147,6 +163,15 @@ typedef struct MemHead { static pthread_t mainid; #endif +#ifdef DEBUG_BACKTRACE +# if defined(__linux__) || defined(__APPLE__) +# include +// Windows is not supported yet. +//# elif defined(_MSV_VER) +//# include +# endif +#endif + typedef struct MemTail { int tag3, pad; } MemTail; @@ -409,6 +434,38 @@ void *MEM_recallocN(void *vmemh, size_t len) return newp; } +#ifdef DEBUG_BACKTRACE +# if defined(__linux__) || defined(__APPLE__) +static void make_memhead_backtrace(MemHead *memh) +{ + memh->backtrace_size = backtrace(memh->backtrace, BACKTRACE_SIZE); +} + +static void print_memhead_backtrace(MemHead *memh) +{ + char **strings; + int i; + + strings = backtrace_symbols(memh->backtrace, memh->backtrace_size); + for (i = 0; i < memh->backtrace_size; i++) { + print_error(" %s\n", strings[i]); + } + + free(strings); +} +# else +static void make_memhead_backtrace(MemHead *memh) +{ + (void) memh; /* Ignored. */ +} + +static void print_memhead_backtrace(MemHead *memh) +{ + (void) memh; /* Ignored. */ +} +# endif /* defined(__linux__) || defined(__APPLE__) */ +#endif /* DEBUG_BACKTRACE */ + static void make_memhead_header(MemHead *memh, size_t len, const char *str) { MemTail *memt; @@ -423,7 +480,11 @@ static void make_memhead_header(MemHead *memh, size_t len, const char *str) #ifdef DEBUG_MEMDUPLINAME memh->need_free_name = 0; #endif - + +#ifdef DEBUG_BACKTRACE + make_memhead_backtrace(memh); +#endif + memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len); memt->tag3 = MEMTAG3; @@ -673,6 +734,9 @@ static void MEM_printmemlist_internal(int pydict) #else print_error("%s len: " SIZET_FORMAT " %p\n", membl->name, SIZET_ARG(membl->len), membl + 1); +#endif +#ifdef DEBUG_BACKTRACE + print_memhead_backtrace(membl); #endif } if (membl->next)