wip: track allocation locations in debug mode

This commit is contained in:
Daan Leijen 2020-02-11 12:19:22 -08:00
parent 4090561975
commit 21a95c7449
10 changed files with 257 additions and 141 deletions

View file

@ -22,18 +22,14 @@ terms of the MIT license. A copy of the license can be found in the file
#define mi_decl_noinline __declspec(noinline)
#define mi_decl_thread __declspec(thread)
#define mi_decl_cache_align __declspec(align(MI_CACHE_LINE))
#include <intrin.h>
#define mi_return_address() _ReturnAddress()
#elif (defined(__GNUC__) && (__GNUC__>=3)) // includes clang and icc
#define mi_decl_noinline __attribute__((noinline))
#define mi_decl_thread __thread
#define mi_decl_cache_align __attribute__((aligned(MI_CACHE_LINE)))
#define mi_return_address() __builtin_return_address(0)
#else
#define mi_decl_noinline
#define mi_decl_thread __thread // hope for the best :-)
#define mi_decl_cache_align
#define mi_return_address()
#endif
@ -135,9 +131,6 @@ void _mi_block_zero_init(const mi_page_t* page, void* p, size_t size);
mi_decl_allocator void* _mi_heapx_malloc(mi_heap_t* heap, size_t size MI_SOURCE_PARAM) mi_attr_noexcept;
mi_decl_allocator void* _mi_heapx_malloc_zero(mi_heap_t* heap, size_t size, bool zero MI_SOURCE_PARAM);
mi_decl_allocator void* _mi_heapx_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool zero MI_SOURCE_PARAM);
mi_decl_allocator void* _mi_heapx_malloc_aligned(mi_heap_t* heap, size_t size, size_t alignment MI_SOURCE_PARAM) mi_attr_noexcept;
mi_decl_allocator void* _mi_heapx_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size MI_SOURCE_PARAM) mi_attr_noexcept;
mi_decl_allocator char* _mi_heapx_strdup(mi_heap_t* heap, const char* s MI_SOURCE_PARAM) mi_attr_noexcept;
#if MI_DEBUG>1
bool _mi_page_is_valid(mi_page_t* page);

View file

@ -25,11 +25,11 @@ terms of the MIT license. A copy of the license can be found in the file
void operator delete(void* p) noexcept { mi_free(p); };
void operator delete[](void* p) noexcept { mi_free(p); };
void* operator new(std::size_t n) noexcept(false) { return mi_new(n); }
void* operator new[](std::size_t n) noexcept(false) { return mi_new(n); }
void* operator new(std::size_t n) noexcept(false) { return mi_source_new(n MI_SOURCE_RET()); }
void* operator new[](std::size_t n) noexcept(false) { return mi_source_new(n MI_SOURCE_RET()); }
void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); }
void* operator new[](std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_new_nothrow(n); }
void* operator new (std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_source_new_nothrow(n MI_SOURCE_RET()); }
void* operator new[](std::size_t n, const std::nothrow_t& tag) noexcept { (void)(tag); return mi_source_new_nothrow(n MI_SOURCE_RET()); }
#if (__cplusplus >= 201402L || _MSC_VER >= 1916)
void operator delete (void* p, std::size_t n) noexcept { mi_free_size(p,n); };
@ -42,10 +42,10 @@ terms of the MIT license. A copy of the license can be found in the file
void operator delete (void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast<size_t>(al)); };
void operator delete[](void* p, std::size_t n, std::align_val_t al) noexcept { mi_free_size_aligned(p, n, static_cast<size_t>(al)); };
void* operator new( std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast<size_t>(al)); }
void* operator new[]( std::size_t n, std::align_val_t al) noexcept(false) { return mi_new_aligned(n, static_cast<size_t>(al)); }
void* operator new (std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast<size_t>(al)); }
void* operator new[](std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_new_aligned_nothrow(n, static_cast<size_t>(al)); }
void* operator new( std::size_t n, std::align_val_t al) noexcept(false) { return mi_source_new_aligned(n, static_cast<size_t>(al) MI_SOURCE_RET()); }
void* operator new[]( std::size_t n, std::align_val_t al) noexcept(false) { return mi_source_new_aligned(n, static_cast<size_t>(al) MI_SOURCE_RET()); }
void* operator new (std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_source_new_aligned_nothrow(n, static_cast<size_t>(al) MI_SOURCE_RET()); }
void* operator new[](std::size_t n, std::align_val_t al, const std::nothrow_t&) noexcept { return mi_source_new_aligned_nothrow(n, static_cast<size_t>(al) MI_SOURCE_RET()); }
#endif
#endif

View file

@ -18,22 +18,22 @@ not accidentally mix pointers from different allocators).
#include <mimalloc.h>
// Standard C allocation
#define malloc(n) mi_malloc(n)
#define calloc(n,c) mi_calloc(n,c)
#define realloc(p,n) mi_realloc(p,n)
#define malloc(n) mi_source_malloc(n MI_SOURCE_LOC())
#define calloc(n,c) mi_source_calloc(n,c MI_SOURCE_LOC())
#define realloc(p,n) mi_source_realloc(p,n MI_SOURCE_LOC())
#define free(p) mi_free(p)
#define strdup(s) mi_strdup(s)
#define strndup(s) mi_strndup(s)
#define realpath(f,n) mi_realpath(f,n)
#define strdup(s) mi_source_strdup(s MI_SOURCE_LOC())
#define strndup(s) mi_source_strndup(s MI_SOURCE_LOC())
#define realpath(f,n) mi_source_realpath(f,n MI_SOURCE_LOC())
// Microsoft extensions
#define _expand(p,n) mi_expand(p,n)
#define _msize(p) mi_usable_size(p)
#define _recalloc(p,n,c) mi_recalloc(p,n,c)
#define _strdup(s) mi_strdup(s)
#define _strndup(s) mi_strndup(s)
#define _strdup(s) mi_source_strdup(s MI_SOURCE_LOC())
#define _strndup(s) mi_source_strndup(s MI_SOURCE_LOC())
#define _wcsdup(s) (wchar_t*)mi_wcsdup((const unsigned short*)(s))
#define _mbsdup(s) mi_mbsdup(s)
#define _dupenv_s(b,n,v) mi_dupenv_s(b,n,v)
@ -54,7 +54,7 @@ not accidentally mix pointers from different allocators).
#define _posix_memalign(p,a,n) mi_posix_memalign(p,a,n)
// Microsoft aligned variants
#define _aligned_malloc(n,a) mi_malloc_aligned(n,a)
#define _aligned_malloc(n,a) mi_source_malloc_aligned(n,a MI_SOURCE_LOC())
#define _aligned_realloc(p,n,a) mi_realloc_aligned(p,n,a)
#define _aligned_recalloc(p,s,n,a) mi_aligned_recalloc(p,s,n,a)
#define _aligned_msize(p,a,o) mi_usable_size(p)

View file

@ -274,10 +274,6 @@ typedef struct mi_segment_s {
// of the blocks to check for buffer overflows.
// ------------------------------------------------------
#if defined(MI_PADDING)
// compressed location:
// lsb=1: bit 63-32: relative file name char* (to `mi_fname_base`), bit 31-1: line number
// lsb=0: bit 63-01: return address
typedef int64_t mi_source_t;
typedef struct mi_padding_s {
uint32_t canary; // encoded block value to check validity of the padding (in case of heap block overflow)
uint32_t delta; // padding bytes before the block. (mi_usable_size(p) - delta == exact allocated bytes)
@ -285,15 +281,9 @@ typedef struct mi_padding_s {
} mi_padding_t;
#define MI_PADDING_SIZE (sizeof(mi_padding_t))
#define MI_PADDING_WSIZE ((MI_PADDING_SIZE + MI_INTPTR_SIZE - 1) / MI_INTPTR_SIZE)
#define MI_SOURCE_PARAM , mi_source_t source
#define MI_SOURCE_ARG , source
#define MI_SOURCE_RET , ((intptr_t)mi_return_address() << (intptr_t)1)
#else
#define MI_PADDING_SIZE 0
#define MI_PADDING_WSIZE 0
#define MI_SOURCE_PARAM
#define MI_SOURCE_ARG
#define MI_SOURCE_RET
#endif
// ------------------------------------------------------

View file

@ -360,6 +360,58 @@ mi_decl_nodiscard mi_decl_export void* mi_new_n(size_t count, size_t size) mi_at
mi_decl_nodiscard mi_decl_export void* mi_new_realloc(void* p, size_t newsize) mi_attr_malloc mi_attr_alloc_size(2);
mi_decl_nodiscard mi_decl_export void* mi_new_reallocn(void* p, size_t newcount, size_t size) mi_attr_malloc mi_attr_alloc_size2(2, 3);
// ---------------------------------------------------------------------------------------------
// Experimental: Debugging API that tracks the source location of an allocation
// ---------------------------------------------------------------------------------------------
typedef struct mi_source_s {
long long src; // packed encoding of the source location
} mi_source_t;
mi_decl_export mi_source_t mi_source_ret(void* return_address);
mi_decl_export mi_source_t mi_source_loc(const char* fname, int lineno);
mi_decl_export void* mi_source_unpack(mi_source_t source, const char** fname, int* lineno);
#ifdef NDEBUG
#define MI_SOURCE_PARAM
#define MI_SOURCE_ARG
#define MI_SOURCE_RET()
#define MI_SOURCE_LOC()
#else
#ifdef _MSC_VER
#include <intrin.h>
#define mi_return_address() _ReturnAddress()
#elif (defined(__GNUC__) && (__GNUC__>=3)) // includes clang and icc
#define mi_return_address() __builtin_return_address(0)
#else
#define mi_return_address() NULL
#endif
#define MI_SOURCE_PARAM , mi_source_t __mi_source
#define MI_SOURCE_ARG , __mi_source
#define MI_SOURCE_RET() , mi_source_ret(mi_return_address())
#define MI_SOURCE_LOC() , mi_source_loc(__FILE__,__LINE__)
#endif
mi_decl_nodiscard mi_decl_export mi_decl_allocator void* mi_source_malloc(size_t size MI_SOURCE_PARAM) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(1);
mi_decl_nodiscard mi_decl_export mi_decl_allocator void* mi_source_calloc(size_t count, size_t size MI_SOURCE_PARAM) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(1, 2);
mi_decl_nodiscard mi_decl_export mi_decl_allocator void* mi_source_realloc(void* p, size_t newsize MI_SOURCE_PARAM) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);
mi_decl_nodiscard mi_decl_export mi_decl_allocator void* mi_source_malloc_aligned(size_t size, size_t alignment MI_SOURCE_PARAM) mi_attr_noexcept;
mi_decl_nodiscard mi_decl_export mi_decl_allocator void* mi_source_reallocn(void* p, size_t count, size_t size MI_SOURCE_PARAM) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2, 3);
mi_decl_nodiscard mi_decl_export char* mi_source_strdup(const char* s MI_SOURCE_PARAM) mi_attr_noexcept;
mi_decl_nodiscard mi_decl_export char* mi_source_strndup(const char* s, size_t n MI_SOURCE_PARAM) mi_attr_noexcept;
mi_decl_nodiscard mi_decl_export char* mi_source_realpath(const char* fname, char* resolved_name MI_SOURCE_PARAM) mi_attr_noexcept;
mi_decl_nodiscard mi_decl_export void* mi_source_new(size_t size MI_SOURCE_PARAM) mi_attr_malloc mi_attr_alloc_size(1);
mi_decl_nodiscard mi_decl_export void* mi_source_new_aligned(size_t size, size_t alignment MI_SOURCE_PARAM) mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2);
mi_decl_nodiscard mi_decl_export void* mi_source_new_nothrow(size_t size MI_SOURCE_PARAM) mi_attr_malloc mi_attr_alloc_size(1);
mi_decl_nodiscard mi_decl_export void* mi_source_new_aligned_nothrow(size_t size, size_t alignment MI_SOURCE_PARAM) mi_attr_malloc mi_attr_alloc_size(1) mi_attr_alloc_align(2);
// ----------------------------------------------------------------------
// end of extern "C"
// ----------------------------------------------------------------------
#ifdef __cplusplus
}
#endif
@ -420,4 +472,7 @@ template<class T1,class T2> bool operator==(const mi_stl_allocator<T1>& , const
template<class T1,class T2> bool operator!=(const mi_stl_allocator<T1>& , const mi_stl_allocator<T2>& ) mi_attr_noexcept { return false; }
#endif // __cplusplus
#endif
#endif // MIMALLOC_H