merge from dev-trace

This commit is contained in:
Daan Leijen 2021-12-10 11:54:41 -08:00
commit d86fc87fa1
7 changed files with 168 additions and 94 deletions

View file

@ -55,7 +55,7 @@ void _mi_error_message(int err, const char* fmt, ...);
#if MI_DEBUG_TRACE > 0
void _mi_stack_trace_capture(void** strace, size_t len, size_t skip);
void _mi_stack_trace_print(const void* const* 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);
#endif
// random.c
@ -152,6 +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);
#if MI_DEBUG>1
bool _mi_page_is_valid(mi_page_t* page);
@ -416,7 +417,7 @@ static inline uintptr_t _mi_ptr_cookie(const void* p) {
----------------------------------------------------------- */
static inline mi_page_t* _mi_heap_get_free_small_page(mi_heap_t* heap, size_t size) {
mi_assert_internal(size <= (MI_SMALL_SIZE_MAX + 2*sizeof(void*))); // +2 for the minimal padding (see MI_PAGES_DIRECT)
mi_assert_internal(size <= (MI_SMALL_SIZE_MAX + MI_PADDING_MINSIZE));
const size_t idx = _mi_wsize_from_size(size);
mi_assert_internal(idx < MI_PAGES_DIRECT);
return heap->pages_free_direct[idx];
@ -484,7 +485,7 @@ static inline mi_page_t* _mi_ptr_page(void* p) {
// Get the block size of a page (special case for huge objects)
static inline size_t mi_page_block_size(const mi_page_t* page) {
const size_t bsize = page->xblock_size;
mi_assert_internal(bsize > 0);
mi_assert_internal(bsize > 0);
if (mi_likely(bsize < MI_HUGE_BLOCK_SIZE)) {
return bsize;
}
@ -680,7 +681,8 @@ 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_message(EFAULT, "corrupted free list entry of size %zub at %p: value 0x%zx\n", mi_page_block_size(page), block, (uintptr_t)next);
_mi_error_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;
}
return next;

View file

@ -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
@ -79,6 +79,7 @@ terms of the MIT license. A copy of the license can be found in the file
// Encoded free lists allow detection of corrupted free lists
// and can detect buffer overflows, modify after free, and double `free`s.
// (It must be enabled if MI_PADDING is enabled as the same mechanism is used to encode the canary.)
#if (MI_SECURE>=3 || MI_DEBUG>=1 || MI_PADDING > 0)
#define MI_ENCODE_FREELIST 1
#endif
@ -418,11 +419,20 @@ typedef struct mi_random_cxt_s {
} mi_random_ctx_t;
// In debug mode there is a padding structure at the end of the blocks to check for buffer overflows
// If MI_PADDING is enabled, there is a padding structure at the end of the blocks to check for buffer overflows
// The full layout is of a block becomes:
//
// |--- data ---------|--- fill ----------|--- struct padding_s -----------------------------------------|
// |.. actual data .. | .. delta bytes .. | canary_lo | .. extra .. | canary | delta | .. stack trace .. |
//
// where the delta bytes are used to align the padding structure and to detect byte precise overflow.
// The `canary` is used to see if `delta` and `strace` are not corrupted, while `canary_lo` can
// detect overflow into the `extra` padding (where the stack trace could remain valid)
#if (MI_PADDING)
typedef struct mi_padding_s {
#if MI_PADDING_EXTRA > 0
uint32_t canary_lo;
uint32_t canary_lo; // extra canary to detect initial overflow
uint8_t extra[MI_PADDING_EXTRA];
#endif
uint32_t canary; // encoded block value to check validity of the delat (in case of overflow)
@ -431,7 +441,7 @@ typedef struct mi_padding_s {
void* strace[MI_DEBUG_TRACE_LEN]; // stack trace at allocation time
#endif
} mi_padding_t;
#define MI_PADDING_MINSIZE (8) // 2*sizeof(uint32_t)
#define MI_PADDING_MINSIZE (8) // 2*sizeof(uint32_t)
#define MI_PADDING_SIZE (sizeof(mi_padding_t))
#else
#define MI_PADDING_MINSIZE (0)
@ -439,6 +449,8 @@ typedef struct mi_padding_s {
#endif
// add 2 more for minimal padding (MI_PADDING && !MI_DEBUG_TRACE && MI_PADDING_EXTRA==0)
// since this is used in secure mode, we optimize this case by allowing
// `heap_malloc_small` to also work with `MI_WSMALL_SIZE_MAX + MI_PADDING_MINSIZE` sizes.
// see `init.c` where all are initialized with an empty page and the check at `heap_malloc_small`.
#define MI_PAGES_DIRECT (MI_SMALL_WSIZE_MAX + 1 + 2)