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.
This commit is contained in:
Sergey Sharybin 2013-05-30 14:27:24 +00:00
parent 7586580241
commit 1be2936298

@ -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 <execinfo.h>
// Windows is not supported yet.
//# elif defined(_MSV_VER)
//# include <DbgHelp.h>
# 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)