From 6b967287c964e4deb9755d35f37998ba9ff06c34 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 28 Sep 2023 12:34:13 +1000 Subject: [PATCH] MEM_guarded_alloc: restore execinfo.h back-trace on Linux/Apple Recently [0] replaced back-traces from `execinfo.h` with ASAN's `__asan_describe_address` since the linking options to hide symbols cause the stack-traces only to include addresses (without functions). Although using ASAN makes sense when enabled, in my tests the stack-traces are sometimes empty. Using CMAKE_BUILD_TYPE=RelWithDebInfo for e.g. wasn't showing a stack-trace for the leak fixed in [1]. A utility is now included to conveniently expand the addresses from these stack traces (`tools/utils/addr2line_backtrace.py`). Restore support for the execinfo stack-trace reporting, used when ASAN is disabled. [0]: 2e79ca320557073ccf00f021dca988be6f361acd [1]: a9f0d19197e83ae6be7c1ccc71770361be16f742 --- .../intern/mallocn_guarded_impl.c | 63 +++++++++++++++++-- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/intern/guardedalloc/intern/mallocn_guarded_impl.c b/intern/guardedalloc/intern/mallocn_guarded_impl.c index 526686a579d..31114f3749e 100644 --- a/intern/guardedalloc/intern/mallocn_guarded_impl.c +++ b/intern/guardedalloc/intern/mallocn_guarded_impl.c @@ -49,7 +49,27 @@ #if defined(_MSC_VER) # define DEBUG_BACKTRACE #else -//#define DEBUG_BACKTRACE +/* Un-comment to report back-traces with leaks, uses ASAN when enabled. + * NOTE: The default linking options cause the stack traces only to include addresses. + * Use `addr2line` to expand into file, line & function identifiers, + * see: `tools/utils/addr2line_backtrace.py` convenience utility. */ +// # define DEBUG_BACKTRACE +#endif + +#ifdef DEBUG_BACKTRACE +# ifdef WITH_ASAN +/* Rely on address sanitizer. */ +# else +# if defined(__linux__) || defined(__APPLE__) +# define DEBUG_BACKTRACE_EXECINFO +# else +# error "DEBUG_BACKTRACE: not supported for this platform!" +# endif +# endif +#endif + +#ifdef DEBUG_BACKTRACE_EXECINFO +# define BACKTRACE_SIZE 100 #endif #ifdef DEBUG_MEMCOUNTER @@ -94,6 +114,12 @@ typedef struct MemHead { #ifdef DEBUG_MEMDUPLINAME int need_free_name, pad; #endif + +#ifdef DEBUG_BACKTRACE_EXECINFO + void *backtrace[BACKTRACE_SIZE]; + int backtrace_size; +#endif + } MemHead; typedef MemHead MemHeadAligned; @@ -102,6 +128,10 @@ typedef struct MemTail { int tag3, pad; } MemTail; +#ifdef DEBUG_BACKTRACE_EXECINFO +# include +#endif + /* --------------------------------------------------------------------- */ /* local functions */ /* --------------------------------------------------------------------- */ @@ -354,6 +384,26 @@ void *MEM_guarded_recallocN_id(void *vmemh, size_t len, const char *str) return newp; } +#ifdef DEBUG_BACKTRACE_EXECINFO +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); +} +#endif /* DEBUG_BACKTRACE_EXECINFO */ + static void make_memhead_header(MemHead *memh, size_t len, const char *str) { MemTail *memt; @@ -370,6 +420,10 @@ static void make_memhead_header(MemHead *memh, size_t len, const char *str) memh->need_free_name = 0; #endif +#ifdef DEBUG_BACKTRACE_EXECINFO + make_memhead_backtrace(memh); +#endif + memt = (MemTail *)(((char *)memh) + sizeof(MemHead) + len); memt->tag3 = MEMTAG3; @@ -720,10 +774,11 @@ static void MEM_guarded_printmemlist_internal(int pydict) SIZET_ARG(membl->len), (void *)(membl + 1)); #endif -#ifdef DEBUG_BACKTRACE -# ifdef WITH_ASAN + +#ifdef DEBUG_BACKTRACE_EXECINFO + print_memhead_backtrace(membl); +#elif defined(DEBUG_BACKTRACE) && defined(WITH_ASAN) __asan_describe_address(membl); -# endif #endif } if (membl->next) {