diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index ffe17b56..e008a529 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -152,7 +152,7 @@ void* _mi_heap_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool mi_block_t* _mi_page_ptr_unalign(const mi_segment_t* segment, const mi_page_t* page, const void* p); bool _mi_free_delayed_block(mi_block_t* block); void _mi_block_zero_init(const mi_page_t* page, void* p, size_t size); -void _mi_error_trace_with_predecessor(const mi_page_t* page, const mi_block_t* block, const char* msg); +void _mi_show_block_trace_with_predecessor(const mi_page_t* page, const mi_block_t* block, const char* msg); #if MI_DEBUG>1 bool _mi_page_is_valid(mi_page_t* page); @@ -681,7 +681,7 @@ static inline mi_block_t* mi_block_next(const mi_page_t* page, const mi_block_t* // check for free list corruption: is `next` at least in the same page? // TODO: check if `next` is `page->block_size` aligned? if (mi_unlikely(next!=NULL && !mi_is_in_same_page(block, next))) { - _mi_error_trace_with_predecessor(page, block, "free block"); + _mi_show_block_trace_with_predecessor(page, block, "free block"); _mi_error_message(EFAULT, "corrupted free list entry of size %zu at %p: value 0x%zx\n", mi_page_block_size(page), block, (uintptr_t)next); next = NULL; } diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index 82ceaac4..4897b6b6 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -61,7 +61,7 @@ terms of the MIT license. A copy of the license can be found in the file #endif #if !defined(MI_DEBUG_TRACE) // store stack trace at each allocation -#define MI_DEBUG_TRACE MI_DEBUG +#define MI_DEBUG_TRACE (0) #endif #if !defined(MI_DEBUG_TRACE_LEN) @@ -70,7 +70,7 @@ terms of the MIT license. A copy of the license can be found in the file #if !defined(MI_PADDING_EXTRA) // use extra padding bytes? (so a stack trace can be preserved or next block corruption prevented) #if MI_DEBUG_TRACE > 0 -#define MI_PADDING_EXTRA (128) +#define MI_PADDING_EXTRA (64) #else #define MI_PADDING_EXTRA (0) #endif diff --git a/src/alloc.c b/src/alloc.c index 9c52f7d1..1d737f76 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -201,7 +201,7 @@ static mi_padding_t* mi_page_decode_padding(const mi_page_t* page, const mi_bloc } #if MI_DEBUG_TRACE > 0 -static void _mi_error_trace(const mi_page_t* page, const mi_block_t* block, const char* msg) { +static void _mi_show_block_trace(const mi_page_t* page, const mi_block_t* block, const char* msg) { size_t bsize; size_t delta; mi_padding_t* padding = mi_page_decode_padding(page, block, &delta, &bsize); @@ -210,7 +210,7 @@ static void _mi_error_trace(const mi_page_t* page, const mi_block_t* block, cons } } #else -static void _mi_error_trace(const mi_page_t* page, const mi_block_t* block) { +static void _mi_show_block_trace(const mi_page_t* page, const mi_block_t* block) { MI_UNUSED(page); MI_UNUSED(block); } #endif @@ -253,7 +253,7 @@ static void mi_check_padding(const mi_page_t* page, const mi_block_t* block) { size_t size; size_t wrong; if (mi_unlikely(!mi_verify_padding(page,block,&size,&wrong))) { - _mi_error_trace(page, block, NULL); + _mi_show_block_trace_with_predecessor(page, block, NULL); _mi_error_message(EFAULT, "buffer overflow in heap block %p of size %zu: write after %zu bytes\n", block, size, wrong ); } } @@ -289,7 +289,7 @@ static void mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, co MI_UNUSED(page); MI_UNUSED(block); MI_UNUSED(min_size); } -static void _mi_error_trace(const mi_page_t* page, const mi_block_t* block, const char* msg) { +static void _mi_show_block_trace(const mi_page_t* page, const mi_block_t* block, const char* msg) { MI_UNUSED(page); MI_UNUSED(block); MI_UNUSED(msg); } #endif @@ -305,12 +305,12 @@ static const mi_block_t* mi_block_predecessor(const mi_page_t* page, const mi_bl } // Used if a free list is corrupted which is usually caused by the previous block(s) -void _mi_error_trace_with_predecessor(const mi_page_t* page, const mi_block_t* block, const char* msg) { +void _mi_show_block_trace_with_predecessor(const mi_page_t* page, const mi_block_t* block, const char* msg) { const mi_block_t* prev = mi_block_predecessor(page,block); if (prev != NULL) { - _mi_error_trace(page, prev, "predecessor block"); + _mi_show_block_trace(page, prev, "predecessor block"); } - _mi_error_trace(page, block, msg); + _mi_show_block_trace(page, block, msg); } @@ -336,7 +336,7 @@ static mi_decl_noinline bool mi_check_is_double_freex(const mi_page_t* page, con mi_list_contains(page, page->local_free, block) || mi_list_contains(page, mi_page_thread_free(page), block)) { - _mi_error_trace(page, block, NULL); + _mi_show_block_trace(page, block, NULL); _mi_error_message(EAGAIN, "double free detected of block %p with size %zu\n", block, mi_page_usable_size_of(page,block)); return true; } diff --git a/src/options.c b/src/options.c index 587abaed..fbd0436a 100644 --- a/src/options.c +++ b/src/options.c @@ -361,15 +361,15 @@ void _mi_stack_trace_capture(void** strace, size_t len, size_t skip) { #include #pragma comment(lib,"dbghelp") void _mi_stack_trace_print(const char* msg, void** strace, size_t len, const mi_block_t* block, size_t bsize, size_t avail) { - _mi_fprintf(NULL, NULL, "trace %s at %p of size %zu (%zub total available), backtrace:\n", + _mi_fprintf(NULL, NULL, "trace %s at %p of size %zu (%zub usable), allocated at:\n", (msg==NULL ? "block" : msg), block, avail, bsize); - HANDLE current_process = GetCurrentProcess(); - SymInitialize(current_process, NULL, TRUE); PSYMBOL_INFO info = (PSYMBOL_INFO)_malloca(sizeof(SYMBOL_INFO) + 256 * sizeof(TCHAR)); if (info==NULL) return; memset(info, 0, sizeof(info)); info->MaxNameLen = 255; info->SizeOfStruct = sizeof(SYMBOL_INFO); + HANDLE current_process = GetCurrentProcess(); + if (!SymInitialize(current_process, NULL, TRUE)) return; for (size_t i = 0; i < len && strace[i] != NULL; i++) { if (SymFromAddr(current_process, (DWORD64)(strace[i]), 0, info)) { _mi_fprintf(NULL, NULL, " %2zu: %8p: %s\n", i, strace[i], info->Name); @@ -378,24 +378,31 @@ void _mi_stack_trace_print(const char* msg, void** strace, size_t len, const mi_ _mi_fprintf(NULL, NULL, " %2zu: %8p: \n", i, strace[i], GetLastError()); } } + SymCleanup(current_process); } #elif (MI_DEBUG_TRACE > 0) && (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)) #include -#define MI_TRACE_LEN (64) +#define MI_MAX_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; // needed for pthreads - void* trace[MI_TRACE_LEN]; - backtrace(trace, MI_TRACE_LEN); + void* trace[MI_MAX_TRACE_LEN]; + size_t trace_len = skip + len; + if (trace_len > len) { trace_len = MI_MAX_TRACE_LEN; } + memset(trace,0,trace_len); + trace_len = backtrace(trace, trace_len); for (size_t i = 0; i < len; i++) { - void* p = (i + skip < MI_TRACE_LEN ? trace[i+skip] : NULL); + void* p = (i + skip < trace_len ? trace[i+skip] : NULL); strace[i] = p; } mi_recurse_exit(); } + void _mi_stack_trace_print(const char* msg, void** strace, size_t len, const mi_block_t* block, size_t bsize, size_t avail) { - _mi_fprintf(NULL, NULL, "trace %s at %p of size %zu (%zub total available), backtrace:\n", + _mi_fprintf(NULL, NULL, "trace %s at %p of size %zu (%zub usable), allocated at:\n", (msg==NULL ? "block" : msg), block, avail, bsize); + while( len > 0 && strace[len-1] == NULL) { len--; } + if (len == 0) return; char** names = backtrace_symbols(strace, len); for (size_t i = 0; i < len && strace[i] != NULL; i++) { _mi_fprintf(NULL, NULL, " %2zu: %8p: %s\n", i, strace[i], (names == NULL || names[i] == NULL ? "" : names[i])); diff --git a/test/main-override-static.c b/test/main-override-static.c index 0fa5a379..5674a084 100644 --- a/test/main-override-static.c +++ b/test/main-override-static.c @@ -230,7 +230,8 @@ int main() { static void invalid_free() { free((void*)0xBADBEEF); - realloc((void*)0xBADBEEF,10); + void* p = realloc((void*)0xBADBEEF,10); + free(p); } static void block_overflow1() { @@ -333,7 +334,7 @@ static void corrupt_free2() { // allocate more.. trying to trigger an allocation from a corrupted entry // this may need many allocations to get there (if at all) for (int i = 0; i < 4096; i++) { - malloc(SZ); + void* p = malloc(SZ); } // free the rest for (int i = 0; i < N; i++) {