add more detailed block info for heap visiting

This commit is contained in:
daan 2020-04-06 23:39:09 -07:00
parent 120af372ab
commit 173978c122
5 changed files with 89 additions and 12 deletions

View File

@ -148,6 +148,7 @@ mi_block_t* _mi_page_ptr_unalign(const mi_segment_t* segment, const mi_page_t* 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);
size_t _mi_path_max(void);
void _mi_page_block_info(const mi_page_t* page, const mi_block_t* block, mi_block_info_t* info);
mi_decl_restrict void* _mi_base_malloc_zero(mi_heap_t* heap, size_t size, bool zero MI_SOURCE_XPARAM) mi_attr_malloc mi_attr_alloc_size(2);
void* _mi_base_realloc_zero(mi_heap_t* heap, void* p, size_t newsize, bool zero MI_SOURCE_XPARAM) mi_attr_alloc_size(2);

View File

@ -282,7 +282,17 @@ typedef struct mi_heap_area_s {
size_t block_size; // size in bytes of each block
} mi_heap_area_t;
typedef bool (mi_cdecl mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, void* block, size_t block_size, void* arg);
// Information about a block
typedef struct mi_block_info_s {
void* block; // start of the block
size_t size; // full size including padding etc.
size_t usable_size; // usable size (available for in-place realloc)
size_t allocated_size; // actual allocated size (only precise in debug mode with padding)
bool valid; // is the block valid? (only detects corrupt blocks with padding enabled)
mi_source_t source; // the source location that allocated this block (only valid in debug mode with padding)
} mi_block_info_t;
typedef bool (mi_cdecl mi_block_visit_fun)(const mi_heap_t* heap, const mi_heap_area_t* area, const mi_block_info_t* block_info, void* arg);
mi_decl_export bool mi_heap_visit_blocks(const mi_heap_t* heap, bool visit_all_blocks, mi_block_visit_fun* visitor, void* arg);

View File

@ -18,6 +18,7 @@ terms of the MIT license. A copy of the license can be found in the file
#include "alloc-override.c"
#undef MI_IN_ALLOC_C
#define MI_PADDING_MAX_VALIDATE (4*1024) // max. bytes validated for overwrites
// ----------------------------------------------------------------------------------------
// Allocation
@ -58,7 +59,7 @@ extern inline void* _mi_page_malloc(mi_heap_t* heap, mi_page_t* page, size_t siz
padding->delta = (uint32_t)(delta);
padding->source = __mi_source;
uint8_t* fill = (uint8_t*)padding - delta;
const size_t maxpad = (delta > 4096 ? 4096 : delta); // set at most N initial padding bytes
const size_t maxpad = (delta > MI_PADDING_MAX_VALIDATE ? MI_PADDING_MAX_VALIDATE : delta); // set at most N initial padding bytes
for (size_t i = 0; i < maxpad; i++) { fill[i] = MI_DEBUG_PADDING; }
#endif
return block;
@ -211,9 +212,13 @@ static inline bool mi_check_is_double_free(const mi_page_t* page, const mi_block
#if defined(MI_PADDING) && defined(MI_ENCODE_FREELIST)
static void mi_check_padding(const mi_page_t* page, const mi_block_t* block);
static bool mi_page_decode_padding(const mi_page_t* page, const mi_block_t* block, size_t* delta, size_t* bsize) {
static const mi_padding_t* mi_page_get_padding(const mi_page_t* page, const mi_block_t* block, size_t* bsize) {
*bsize = mi_page_usable_block_size(page);
const mi_padding_t* const padding = (mi_padding_t*)((uint8_t*)block + *bsize);
return (mi_padding_t*)((uint8_t*)block + *bsize);
}
static bool mi_page_decode_padding(const mi_page_t* page, const mi_block_t* block, size_t* delta, size_t* bsize) {
const mi_padding_t* const padding = mi_page_get_padding(page, block, bsize);
*delta = padding->delta;
return ((uint32_t)mi_ptr_encode(page,block,page->keys) == padding->canary && *delta <= *bsize);
}
@ -237,7 +242,7 @@ static bool mi_verify_padding(const mi_page_t* page, const mi_block_t* block, si
mi_assert_internal(bsize >= delta);
*size = bsize - delta;
uint8_t* fill = (uint8_t*)block + bsize - delta;
const size_t maxpad = (delta > MI_MAX_ALIGN_SIZE ? MI_MAX_ALIGN_SIZE : delta); // check at most the first N padding bytes
const size_t maxpad = (delta > MI_PADDING_MAX_VALIDATE ? MI_PADDING_MAX_VALIDATE : delta); // check at most the first N padding bytes
for (size_t i = 0; i < maxpad; i++) {
if (fill[i] != MI_DEBUG_PADDING) {
*wrong = bsize - delta + i;
@ -323,6 +328,25 @@ static void mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, co
}
#endif
void _mi_page_block_info(const mi_page_t* page, const mi_block_t* block, mi_block_info_t* info) {
mi_assert_internal(page!=NULL);
mi_assert_internal(block!=NULL);
mi_assert_internal(info!=NULL);
memset(info, 0, sizeof(*info));
info->block = (void*)block;
info->size = mi_page_block_size(page);
#if MI_PADDING
const mi_padding_t* padding = mi_page_get_padding(page, block, &info->usable_size);
info->source = padding->source;
size_t wrong;
info->valid = mi_verify_padding(page, block, &info->allocated_size, &wrong);
#else
info->usable_size = mi_usable_size(block);
info->allocated_size = info->usable_size;
#endif
}
// ------------------------------------------------------
// Free
// ------------------------------------------------------

View File

@ -468,7 +468,10 @@ static bool mi_heap_area_visit_blocks(const mi_heap_area_ex_t* xarea, mi_block_v
if (page->capacity == 1) {
// optimize page with one block
mi_assert_internal(page->used == 1 && page->free == NULL);
return visitor(mi_page_heap(page), area, pstart, bsize, arg);
mi_block_info_t info;
mi_block_t* block = (mi_block_t*)(pstart);
_mi_page_block_info(page, block, &info);
return visitor(mi_page_heap(page), area, &info, arg);
}
// create a bitmap of free blocks.
@ -501,8 +504,10 @@ static bool mi_heap_area_visit_blocks(const mi_heap_area_ex_t* xarea, mi_block_v
}
else if ((m & ((uintptr_t)1 << bit)) == 0) {
used_count++;
uint8_t* block = pstart + (i * bsize);
if (!visitor(mi_page_heap(page), area, block, bsize, arg)) return false;
mi_block_info_t info;
mi_block_t* block = (mi_block_t*)(pstart + (i * bsize));
_mi_page_block_info(page, block, &info);
if (!visitor(mi_page_heap(page), area, &info, arg)) return false;
}
}
mi_assert_internal(page->used == used_count);
@ -522,7 +527,7 @@ static bool mi_heap_visit_areas_page(mi_heap_t* heap, mi_page_queue_t* pq, mi_pa
xarea.area.reserved = page->reserved * bsize;
xarea.area.committed = page->capacity * bsize;
xarea.area.blocks = _mi_page_start(_mi_page_segment(page), page, NULL);
xarea.area.used = page->used;
xarea.area.used = page->used * bsize;
xarea.area.block_size = bsize;
return fun(heap, &xarea, arg);
}
@ -542,7 +547,7 @@ typedef struct mi_visit_blocks_args_s {
static bool mi_heap_area_visitor(const mi_heap_t* heap, const mi_heap_area_ex_t* xarea, void* arg) {
mi_visit_blocks_args_t* args = (mi_visit_blocks_args_t*)arg;
if (!args->visitor(heap, &xarea->area, NULL, xarea->area.block_size, args->arg)) return false;
if (!args->visitor(heap, &xarea->area, NULL, args->arg)) return false;
if (args->visit_blocks) {
return mi_heap_area_visit_blocks(xarea, args->visitor, args->arg);
}

View File

@ -7,6 +7,44 @@
#include <mimalloc.h>
#include <mimalloc-override.h> // redefines malloc etc.
typedef struct mi_visit_info_s {
size_t area_count;
size_t block_count;
} mi_visit_info_t;
static bool visit(const mi_heap_t* heap, const mi_heap_area_t* area, const mi_block_info_t* info, void* arg) {
mi_visit_info_t* varg = (mi_visit_info_t*)(arg);
if (info==NULL) {
printf(varg->area_count==0 ? " {" : " ]\n}\n,{");
varg->area_count++;
varg->block_count = 0;
printf("\"area\": %zu, \"start\": 0x%p, \"block_size\": %zu, \"used_size\": %zu,\n \"reserved\": %zu, \"committed\": %zu,", varg->area_count, area->blocks, area->block_size, area->used, area->reserved, area->committed);
printf(" \"blocks\": [\n");
}
else {
printf(varg->block_count==0 ? " {" : " ,{");
varg->block_count++;
printf("\"block\": 0x%p, \"valid\": %s, \"size\": %zu, \"usable_size\": %zu, \"allocated_size\": %zu,\n ", info->block, info->valid ? "true" : "false", info->size, info->usable_size, info->allocated_size);
int lineno;
const char* fname;
void* ret = mi_source_unpack(info->source, &fname, &lineno);
if (fname!=NULL) printf("\"source\": \"%s:%i\" }\n", fname, lineno);
else if (ret != NULL) printf("\"source\": \"(%p)\" }\n", ret);
else printf("\"source\": \"\" }\n");
}
}
static void mi_heap_to_json(mi_heap_t* heap) {
if (heap==NULL) heap = mi_heap_get_default();
mi_visit_info_t info = { 0, 0 };
printf("[\n");
mi_heap_visit_blocks(heap, true, &visit, &info);
printf(info.area_count==0 ? "]\n" : " ] }\n]\n");
}
static void double_free1();
static void double_free2();
static void corrupt_free();
@ -22,7 +60,7 @@ int main() {
// double_free2();
// corrupt_free();
// block_overflow1();
block_overflow2();
// block_overflow2();
// dangling_ptr_write();
void* p1 = malloc(78);
@ -52,7 +90,6 @@ static void block_overflow1() {
p[18] = 0;
free(p);
}
static void block_overflow2() {
void* p[100];
for (int i = 0; i < 100; i++) {