mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-05-10 09:19:31 +03:00
Merge branch 'dev-trace' into dev-slice-trace
This commit is contained in:
commit
66c88eec06
5 changed files with 30 additions and 22 deletions
|
@ -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);
|
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);
|
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_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
|
#if MI_DEBUG>1
|
||||||
bool _mi_page_is_valid(mi_page_t* page);
|
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?
|
// check for free list corruption: is `next` at least in the same page?
|
||||||
// TODO: check if `next` is `page->block_size` aligned?
|
// TODO: check if `next` is `page->block_size` aligned?
|
||||||
if (mi_unlikely(next!=NULL && !mi_is_in_same_page(block, next))) {
|
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);
|
_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;
|
next = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||||
#endif
|
#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
|
#define MI_DEBUG_TRACE (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(MI_DEBUG_TRACE_LEN)
|
#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 !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
|
#if MI_DEBUG_TRACE > 0
|
||||||
#define MI_PADDING_EXTRA (128)
|
#define MI_PADDING_EXTRA (64)
|
||||||
#else
|
#else
|
||||||
#define MI_PADDING_EXTRA (0)
|
#define MI_PADDING_EXTRA (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
16
src/alloc.c
16
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
|
#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 bsize;
|
||||||
size_t delta;
|
size_t delta;
|
||||||
mi_padding_t* padding = mi_page_decode_padding(page, block, &delta, &bsize);
|
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
|
#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);
|
MI_UNUSED(page); MI_UNUSED(block);
|
||||||
}
|
}
|
||||||
#endif
|
#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 size;
|
||||||
size_t wrong;
|
size_t wrong;
|
||||||
if (mi_unlikely(!mi_verify_padding(page,block,&size,&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 );
|
_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);
|
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);
|
MI_UNUSED(page); MI_UNUSED(block); MI_UNUSED(msg);
|
||||||
}
|
}
|
||||||
#endif
|
#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)
|
// 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);
|
const mi_block_t* prev = mi_block_predecessor(page,block);
|
||||||
if (prev != NULL) {
|
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, page->local_free, block) ||
|
||||||
mi_list_contains(page, mi_page_thread_free(page), 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));
|
_mi_error_message(EAGAIN, "double free detected of block %p with size %zu\n", block, mi_page_usable_size_of(page,block));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -361,15 +361,15 @@ void _mi_stack_trace_capture(void** strace, size_t len, size_t skip) {
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
#pragma comment(lib,"dbghelp")
|
#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) {
|
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);
|
(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));
|
PSYMBOL_INFO info = (PSYMBOL_INFO)_malloca(sizeof(SYMBOL_INFO) + 256 * sizeof(TCHAR));
|
||||||
if (info==NULL) return;
|
if (info==NULL) return;
|
||||||
memset(info, 0, sizeof(info));
|
memset(info, 0, sizeof(info));
|
||||||
info->MaxNameLen = 255;
|
info->MaxNameLen = 255;
|
||||||
info->SizeOfStruct = sizeof(SYMBOL_INFO);
|
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++) {
|
for (size_t i = 0; i < len && strace[i] != NULL; i++) {
|
||||||
if (SymFromAddr(current_process, (DWORD64)(strace[i]), 0, info)) {
|
if (SymFromAddr(current_process, (DWORD64)(strace[i]), 0, info)) {
|
||||||
_mi_fprintf(NULL, NULL, " %2zu: %8p: %s\n", i, strace[i], info->Name);
|
_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: <unknown address: error: 0x%04x>\n", i, strace[i], GetLastError());
|
_mi_fprintf(NULL, NULL, " %2zu: %8p: <unknown address: error: 0x%04x>\n", i, strace[i], GetLastError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SymCleanup(current_process);
|
||||||
}
|
}
|
||||||
#elif (MI_DEBUG_TRACE > 0) && (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__))
|
#elif (MI_DEBUG_TRACE > 0) && (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__))
|
||||||
#include <execinfo.h>
|
#include <execinfo.h>
|
||||||
#define MI_TRACE_LEN (64)
|
#define MI_MAX_TRACE_LEN (64)
|
||||||
void _mi_stack_trace_capture(void** strace, size_t len, size_t skip) {
|
void _mi_stack_trace_capture(void** strace, size_t len, size_t skip) {
|
||||||
if (_mi_preloading()) return;
|
if (_mi_preloading()) return;
|
||||||
if (!mi_recurse_enter()) return; // needed for pthreads
|
if (!mi_recurse_enter()) return; // needed for pthreads
|
||||||
void* trace[MI_TRACE_LEN];
|
void* trace[MI_MAX_TRACE_LEN];
|
||||||
backtrace(trace, MI_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++) {
|
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;
|
strace[i] = p;
|
||||||
}
|
}
|
||||||
mi_recurse_exit();
|
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) {
|
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);
|
(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);
|
char** names = backtrace_symbols(strace, len);
|
||||||
for (size_t i = 0; i < len && strace[i] != NULL; i++) {
|
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 ? "<unknown>" : names[i]));
|
_mi_fprintf(NULL, NULL, " %2zu: %8p: %s\n", i, strace[i], (names == NULL || names[i] == NULL ? "<unknown>" : names[i]));
|
||||||
|
|
|
@ -230,7 +230,8 @@ int main() {
|
||||||
|
|
||||||
static void invalid_free() {
|
static void invalid_free() {
|
||||||
free((void*)0xBADBEEF);
|
free((void*)0xBADBEEF);
|
||||||
realloc((void*)0xBADBEEF,10);
|
void* p = realloc((void*)0xBADBEEF,10);
|
||||||
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void block_overflow1() {
|
static void block_overflow1() {
|
||||||
|
@ -333,7 +334,7 @@ static void corrupt_free2() {
|
||||||
// allocate more.. trying to trigger an allocation from a corrupted entry
|
// allocate more.. trying to trigger an allocation from a corrupted entry
|
||||||
// this may need many allocations to get there (if at all)
|
// this may need many allocations to get there (if at all)
|
||||||
for (int i = 0; i < 4096; i++) {
|
for (int i = 0; i < 4096; i++) {
|
||||||
malloc(SZ);
|
void* p = malloc(SZ);
|
||||||
}
|
}
|
||||||
// free the rest
|
// free the rest
|
||||||
for (int i = 0; i < N; i++) {
|
for (int i = 0; i < N; i++) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue