mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-07-06 11:34:38 +03:00
stronger secure mode when defining MI_SECURE=4: checks for double free, corrupted free list, and invalid pointer frees. Performance is impacted but not too much -- more perf testing is needed
This commit is contained in:
parent
fdfa6ed260
commit
2affdbbd2e
8 changed files with 121 additions and 20 deletions
49
src/alloc.c
49
src/alloc.c
|
@ -124,10 +124,50 @@ mi_decl_allocator void* mi_zalloc(size_t size) mi_attr_noexcept {
|
|||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Check for double free in secure mode
|
||||
// ------------------------------------------------------
|
||||
|
||||
#if MI_SECURE>=4
|
||||
static bool mi_list_contains(const mi_page_t* page, const mi_block_t* list, const mi_block_t* elem) {
|
||||
while (list != NULL) {
|
||||
if (elem==list) return true;
|
||||
list = mi_block_next(page, list);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static mi_decl_noinline void mi_free_check_blockx(const mi_page_t* page, const mi_block_t* block, const mi_block_t* n) {
|
||||
size_t psize;
|
||||
uint8_t* pstart = _mi_page_start(_mi_page_segment(page), page, &psize);
|
||||
if ((uint8_t*)n >= pstart && (uint8_t*)n < (pstart + psize)) {
|
||||
// Suspicious: the decoded value is in the same page.
|
||||
// Walk the free lists to see if it is already freed
|
||||
if (mi_list_contains(page, page->free, n) ||
|
||||
mi_list_contains(page, page->local_free, n) ||
|
||||
mi_list_contains(page, (const mi_block_t*)mi_atomic_read_ptr_relaxed(mi_atomic_cast(void*,&page->thread_free)), n))
|
||||
{
|
||||
_mi_fatal_error("double free detected of block %p with size %zu\n", block, page->block_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void mi_free_check_block(const mi_page_t* page, const mi_block_t* block) {
|
||||
mi_block_t* n = (mi_block_t*)(block->next ^ page->cookie);
|
||||
if (n!=NULL && mi_is_in_same_segment(block, n)) { // quick check
|
||||
// Suspicous: decoded value in block is in the same segment, maybe a double free?
|
||||
mi_free_check_blockx(page, block, n);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Free
|
||||
// ------------------------------------------------------
|
||||
|
||||
|
||||
// multi-threaded free
|
||||
static mi_decl_noinline void _mi_free_block_mt(mi_page_t* page, mi_block_t* block)
|
||||
{
|
||||
|
@ -251,14 +291,16 @@ void mi_free(void* p) mi_attr_noexcept
|
|||
|
||||
#if (MI_DEBUG>0)
|
||||
if (mi_unlikely(!mi_is_in_heap_region(p))) {
|
||||
_mi_warning_message("possibly trying to mi_free a pointer that does not point to a valid heap region: 0x%p\n"
|
||||
_mi_warning_message("possibly trying to free a pointer that does not point to a valid heap region: 0x%p\n"
|
||||
"(this may still be a valid very large allocation (over 64MiB))\n", p);
|
||||
if (mi_likely(_mi_ptr_cookie(segment) == segment->cookie)) {
|
||||
_mi_warning_message("(yes, the previous pointer 0x%p was valid after all)\n", p);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if (MI_DEBUG>0 || MI_SECURE>=4)
|
||||
if (mi_unlikely(_mi_ptr_cookie(segment) != segment->cookie)) {
|
||||
_mi_error_message("trying to mi_free a pointer that does not point to a valid heap space: %p\n", p);
|
||||
_mi_error_message("trying to free a pointer that does not point to a valid heap space: %p\n", p);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
@ -278,6 +320,9 @@ void mi_free(void* p) mi_attr_noexcept
|
|||
if (mi_likely(tid == segment->thread_id && page->flags.full_aligned == 0)) { // the thread id matches and it is not a full page, nor has aligned blocks
|
||||
// local, and not full or aligned
|
||||
mi_block_t* block = (mi_block_t*)p;
|
||||
#if MI_SECURE>=4
|
||||
mi_free_check_block(page,block);
|
||||
#endif
|
||||
mi_block_set_next(page, block, page->local_free);
|
||||
page->local_free = block;
|
||||
page->used--;
|
||||
|
|
|
@ -285,6 +285,14 @@ void _mi_assert_fail(const char* assertion, const char* fname, unsigned line, co
|
|||
}
|
||||
#endif
|
||||
|
||||
mi_attr_noreturn void _mi_fatal_error(const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
mi_vfprintf(NULL, "mimalloc: fatal: ", fmt, args);
|
||||
va_end(args);
|
||||
exit(99);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Initialize options by checking the environment
|
||||
// --------------------------------------------------------
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue