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]: 2e79ca3205
[1]: a9f0d19197
This commit is contained in:
Campbell Barton
2023-09-28 12:34:13 +10:00
parent c4a67b377b
commit 6b967287c9

View File

@@ -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 <execinfo.h>
#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) {