From ea75c745e16f100e1bffe7c8aad33f6ecaa687b5 Mon Sep 17 00:00:00 2001 From: Daan Leijen Date: Thu, 9 Dec 2021 17:26:13 -0800 Subject: [PATCH] add tracing on linux and freebsd --- CMakeLists.txt | 32 +++++++++++++++++++++++++++++--- include/mimalloc-types.h | 2 +- src/options.c | 31 +++++++++++++++++++++++++++++-- test/test-stress.c | 5 ++++- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c2c6cfc..9bf903c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,10 +21,14 @@ option(MI_BUILD_OBJECT "Build object library" ON) option(MI_BUILD_TESTS "Build test executables" ON) option(MI_DEBUG_TSAN "Build with thread sanitizer (needs clang)" OFF) option(MI_DEBUG_UBSAN "Build with undefined-behavior sanitizer (needs clang++)" OFF) +option(MI_DEBUG_TRACE "Store allocation stack trace in each heap block to debug heap block overflows or corruption" OFF) option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF) option(MI_INSTALL_TOPLEVEL "Install directly into $CMAKE_INSTALL_PREFIX instead of PREFIX/lib/mimalloc-version" OFF) option(MI_USE_LIBATOMIC "Explicitly link with -latomic (on older systems)" OFF) +set(MI_PADDING_EXTRA 0 CACHE STRING "Specify extra bytes for padding in each heap block (to debug heap block overflows)") + + include(GNUInstallDirs) include("cmake/mimalloc-config-version.cmake") @@ -120,6 +124,21 @@ if(MI_DEBUG_FULL) list(APPEND mi_defines MI_DEBUG=3) # full invariant checking endif() +if(MI_DEBUG_TRACE) + if (APPLE) + message(WARNING "Cannot enable MI_DEBUG_TRACE on Apple") + set(MI_DEBUG_TRACE OFF) + else() + message(STATUS "Enable allocation trace in each heap block (MI_DEBUG_TRACE=ON)") + list(APPEND mi_defines MI_DEBUG_TRACE=1) + endif() +endif() + +if(MI_PADDING_EXTRA) + message(STATUS "Add extra debug padding to each heap block (MI_PADDING_EXTRA=${MI_PADDING_EXTRA})") + list(APPEND mi_defines MI_PADDING_EXTRA=${MI_PADDING_EXTRA}) +endif() + if(NOT MI_PADDING) message(STATUS "Disable padding of heap blocks in debug mode (MI_PADDING=OFF)") list(APPEND mi_defines MI_PADDING=0) @@ -212,9 +231,15 @@ if(WIN32) else() if(NOT ${CMAKE_C_COMPILER} MATCHES "android") list(APPEND mi_libraries pthread) - find_library(LIBRT rt) - if(LIBRT) - list(APPEND mi_libraries ${LIBRT}) + find_library(MI_LIBRT rt) + if(MI_LIBRT) + list(APPEND mi_libraries ${MI_LIBRT}) + endif() + if(MI_DEBUG_TRACE) + find_library(MI_LIBEXECINFO NAMES execinfo) + if (MI_LIBEXECINFO) # on freeBSD + list(APPEND mi_libraries ${MI_LIBEXECINFO}) + endif() endif() endif() endif() @@ -270,6 +295,7 @@ else() message(STATUS "C Compiler : ${CMAKE_C_COMPILER}") endif() message(STATUS "Compiler flags : ${mi_cflags}") +message(STATUS "Compiler defines : ${mi_defines}") message(STATUS "Build targets : ${mi_build_targets}") message(STATUS "") diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index f480ad7d..a5cf0ede 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -60,7 +60,7 @@ terms of the MIT license. A copy of the license can be found in the file #define MI_PADDING 1 #endif -#if !defined(MI_DEBUG_TRACE) // store stack trace at each allocation +#if !defined(MI_DEBUG_TRACE) // store stack trace at each allocation #define MI_DEBUG_TRACE MI_DEBUG #endif diff --git a/src/options.c b/src/options.c index 799f69a3..0bc80aaf 100644 --- a/src/options.c +++ b/src/options.c @@ -358,6 +358,7 @@ void _mi_stack_trace_capture(void** strace, size_t len, size_t skip) { #include #pragma comment(lib,"dbghelp") void _mi_stack_trace_print(const void* const* strace, size_t len, const mi_block_t* block, size_t bsize, size_t avail) { + _mi_fprintf(NULL, NULL, "trace for block %p of size %zu (%zu total in block), allocated at:\n", block, avail, bsize); HANDLE current_process = GetCurrentProcess(); SymInitialize(current_process, NULL, TRUE); PSYMBOL_INFO info = (PSYMBOL_INFO)_malloca(sizeof(SYMBOL_INFO) + 256 * sizeof(TCHAR)); @@ -365,7 +366,6 @@ void _mi_stack_trace_print(const void* const* strace, size_t len, const mi_block memset(info, 0, sizeof(info)); info->MaxNameLen = 255; info->SizeOfStruct = sizeof(SYMBOL_INFO); - _mi_fprintf(NULL, NULL, "for block %p of %zu allocated bytes (%zu total in block), allocated at:\n", block, avail, bsize); for (size_t i = 0; i < len && strace[i] != NULL; i++) { if (SymFromAddr(current_process, (DWORD64)(strace[i]), 0, info)) { _mi_fprintf(NULL, NULL, " frame %2zu: %8p: %s\n", i, strace[i], info->Name); @@ -375,10 +375,37 @@ void _mi_stack_trace_print(const void* const* strace, size_t len, const mi_block } } } +#elif (MI_DEBUG_TRACE > 0) && (defined(__linux__) || defined(__FreeBSD__)) +#include +#define MI_TRACE_LEN (64) +void _mi_stack_trace_capture(void** strace, size_t len, size_t skip) { + if (_mi_preloading()) return; + if (!mi_recurse_enter()) return; + void* trace[MI_TRACE_LEN]; + backtrace(trace, MI_TRACE_LEN); + skip += 4; + for (size_t i = 0; i < len; i++) { + void* p = (i + skip < MI_TRACE_LEN ? trace[i+skip] : NULL); + strace[i] = p; + } + mi_recurse_exit(); +} +void _mi_stack_trace_print(const void* const* strace, size_t len, const mi_block_t* block, size_t bsize, size_t avail) { + _mi_fprintf(NULL, NULL, "trace for block %p of size %zu (%zu total in block), allocated at:\n", block, avail, bsize); + char** names = backtrace_symbols((void**)strace, len); + for (size_t i = 0; i < len && strace[i] != NULL; i++) { + _mi_fprintf(NULL, NULL, " frame %2zu: %8p: %s\n", i, strace[i], (names[i] == NULL ? "" : names[i])); + } +} #else -void _mi_capture_stack_trace(void** strace, size_t len, size_t skip) { +void _mi_stack_trace_capture(void** strace, size_t len, size_t skip) { MI_UNUSED(strace); MI_UNUSED(len); MI_UNUSED(skip); } +void _mi_stack_trace_print(const void* const* strace, size_t len, const mi_block_t* block, size_t bsize, size_t avail) { + MI_UNUSED(strace); MI_UNUSED(len); MI_UNUSED(block); + MI_UNUSED(bsize); MI_UNUSED(avail); +} + #endif // -------------------------------------------------------- diff --git a/test/test-stress.c b/test/test-stress.c index 498b7ec6..e35b659c 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -103,7 +103,10 @@ static void* alloc_items(size_t items, random_t r) { for (uintptr_t i = 0; i < items; i++) { p[i] = (items - i) ^ cookie; } - } + if (pick(r)%1000 <= 1) { + p[items+1] = 42; // overflow + } + } return p; }