fix double free check in secure = 4 mode; inline _mi_ptr_cookie

This commit is contained in:
daan 2019-10-19 08:34:18 -07:00
parent 2affdbbd2e
commit 25246070ae
4 changed files with 45 additions and 22 deletions

View file

@ -137,28 +137,32 @@ static bool mi_list_contains(const mi_page_t* page, const mi_block_t* list, cons
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) {
static mi_decl_noinline bool mi_check_double_freex(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.
if (n == NULL || ((uint8_t*)n >= pstart && (uint8_t*)n < (pstart + psize))) {
// Suspicious: the decoded value is in the same page (or NULL).
// 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))
if (mi_list_contains(page, page->free, block) ||
mi_list_contains(page, page->local_free, block) ||
mi_list_contains(page, (const mi_block_t*)mi_atomic_read_ptr_relaxed(mi_atomic_cast(void*,&page->thread_free)), block))
{
_mi_fatal_error("double free detected of block %p with size %zu\n", block, page->block_size);
return true;
}
}
return false;
}
static inline void mi_free_check_block(const mi_page_t* page, const mi_block_t* block) {
static inline bool mi_check_double_free(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;
if (((uintptr_t)n & (MI_INTPTR_SIZE-1))==0 && // quick check
(n==NULL || mi_is_in_same_segment(block, n)))
{
// Suspicous: decoded value in block is in the same segment (or NULL) -- maybe a double free?
return mi_check_double_freex(page, block, n);
}
return false;
}
#endif
@ -320,8 +324,8 @@ 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);
#if MI_SECURE>=4
if (mi_check_double_free(page,block)) return;
#endif
mi_block_set_next(page, block, page->local_free);
page->local_free = block;

View file

@ -184,10 +184,6 @@ uintptr_t _mi_random_init(uintptr_t seed /* can be zero */) {
return x;
}
uintptr_t _mi_ptr_cookie(const void* p) {
return ((uintptr_t)p ^ _mi_heap_main.cookie);
}
/* -----------------------------------------------------------
Initialization and freeing of the thread local heaps
----------------------------------------------------------- */