From c5a2d11193da2335741a6c66fed8d88c6dd53764 Mon Sep 17 00:00:00 2001 From: daanx Date: Mon, 9 Dec 2024 20:40:26 -0800 Subject: [PATCH] add extra checks for valid pointers in the pagemap, add max_vabits and debug_commit_full_pagemap options --- ide/vs2022/mimalloc-override.vcxproj.filters | 4 ++- ide/vs2022/mimalloc.vcxproj.filters | 4 ++- include/mimalloc.h | 4 ++- include/mimalloc/internal.h | 1 + src/options.c | 2 ++ src/page-map.c | 37 +++++++++++--------- 6 files changed, 33 insertions(+), 19 deletions(-) diff --git a/ide/vs2022/mimalloc-override.vcxproj.filters b/ide/vs2022/mimalloc-override.vcxproj.filters index 0e63822c..fb48e98f 100644 --- a/ide/vs2022/mimalloc-override.vcxproj.filters +++ b/ide/vs2022/mimalloc-override.vcxproj.filters @@ -58,7 +58,9 @@ Sources - + + Sources + diff --git a/ide/vs2022/mimalloc.vcxproj.filters b/ide/vs2022/mimalloc.vcxproj.filters index 7fc4ba9c..06b0364f 100644 --- a/ide/vs2022/mimalloc.vcxproj.filters +++ b/ide/vs2022/mimalloc.vcxproj.filters @@ -58,7 +58,9 @@ Sources - + + Sources + diff --git a/include/mimalloc.h b/include/mimalloc.h index 907ffadb..c11353b7 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -380,7 +380,9 @@ typedef enum mi_option_e { mi_option_target_segments_per_thread, // experimental (=0) mi_option_reclaim_on_free, // allow to reclaim an abandoned segment on a free (=1) mi_option_full_page_retain, // retain N full pages per size class (=2) - mi_option_max_page_candidates, // max candidate pages to consider for allocation (=4) + mi_option_max_page_candidates, // max candidate pages to consider for allocation (=4) + mi_option_max_vabits, // max virtual address bits to consider in user space (=48) + mi_option_debug_commit_full_pagemap, // commit the full pagemap to catch invalid pointer uses (=0) _mi_option_last, // legacy option names mi_option_large_os_pages = mi_option_allow_large_os_pages, diff --git a/include/mimalloc/internal.h b/include/mimalloc/internal.h index c6d9ae36..c189a082 100644 --- a/include/mimalloc/internal.h +++ b/include/mimalloc/internal.h @@ -459,6 +459,7 @@ static inline mi_page_t* _mi_checked_ptr_page(const void* p) { } static inline mi_page_t* _mi_ptr_page(const void* p) { + mi_assert_internal(p==NULL || mi_is_in_heap_region(p)); #if MI_DEBUG || defined(__APPLE__) return _mi_checked_ptr_page(p); #else diff --git a/src/options.c b/src/options.c index f2e9297f..8fcee452 100644 --- a/src/options.c +++ b/src/options.c @@ -160,6 +160,8 @@ static mi_option_desc_t options[_mi_option_last] = { 1, UNINIT, MI_OPTION_LEGACY(reclaim_on_free, abandoned_reclaim_on_free) },// reclaim an abandoned segment on a free { 2, UNINIT, MI_OPTION(full_page_retain) }, { 4, UNINIT, MI_OPTION(max_page_candidates) }, + { 0, UNINIT, MI_OPTION(max_vabits) }, + { 0, UNINIT, MI_OPTION(debug_commit_full_pagemap) }, }; static void mi_option_init(mi_option_desc_t* desc); diff --git a/src/page-map.c b/src/page-map.c index 475e8fc2..181db7f0 100644 --- a/src/page-map.c +++ b/src/page-map.c @@ -20,8 +20,11 @@ static mi_bitmap_t mi_page_map_commit = { MI_ATOMIC_VAR_INIT(MI_BITMAP_DEFAULT_C { 0 }, { {MI_ATOMIC_VAR_INIT(0)} }, {{{ MI_ATOMIC_VAR_INIT(0) }}} }; bool _mi_page_map_init(void) { - size_t vbits = _mi_os_virtual_address_bits(); - if (vbits >= 48) vbits = 47; + size_t vbits = (size_t)mi_option_get_clamp(mi_option_max_vabits, 0, MI_SIZE_BITS); + if (vbits == 0) { + vbits = _mi_os_virtual_address_bits(); + if (vbits >= 48) { vbits = 47; } + } // 1 byte per block = 2 GiB for 128 TiB address space (48 bit = 256 TiB address space) // 64 KiB for 4 GiB address space (on 32-bit) mi_page_map_max_address = (void*)(MI_PU(1) << vbits); @@ -30,7 +33,7 @@ bool _mi_page_map_init(void) { mi_page_map_entries_per_commit_bit = _mi_divide_up(page_map_size, MI_BITMAP_DEFAULT_BIT_COUNT); // mi_bitmap_init(&mi_page_map_commit, MI_BITMAP_MIN_BIT_COUNT, true); - mi_page_map_all_committed = true; // (page_map_size <= 1*MI_MiB); // _mi_os_has_overcommit(); // commit on-access on Linux systems? + mi_page_map_all_committed = (page_map_size <= 1*MI_MiB || mi_option_is_enabled(mi_option_debug_commit_full_pagemap)); // _mi_os_has_overcommit(); // commit on-access on Linux systems? _mi_page_map = (uint8_t*)_mi_os_alloc_aligned(page_map_size, 1, mi_page_map_all_committed, true, &mi_page_map_memid); if (_mi_page_map==NULL) { _mi_error_message(ENOMEM, "unable to reserve virtual memory for the page map (%zu KiB)\n", page_map_size / MI_KiB); @@ -52,26 +55,28 @@ bool _mi_page_map_init(void) { } static void mi_page_map_ensure_committed(size_t idx, size_t slice_count) { - // is the page map area that contains the page address committed? - if (!mi_page_map_all_committed) { - const size_t commit_bit_idx_lo = idx / mi_page_map_entries_per_commit_bit; - const size_t commit_bit_idx_hi = (idx + slice_count - 1) / mi_page_map_entries_per_commit_bit; - for (size_t i = commit_bit_idx_lo; i <= commit_bit_idx_hi; i++) { // per bit to avoid crossing over bitmap chunks - if (mi_bitmap_is_clearN(&mi_page_map_commit, i, 1)) { - // this may race, in which case we do multiple commits (which is ok) + // is the page map area that contains the page address committed? + // we always set the commit bits so we can track what ranges are in-use. + // we only actually commit if the map wasn't committed fully already. + const size_t commit_bit_idx_lo = idx / mi_page_map_entries_per_commit_bit; + const size_t commit_bit_idx_hi = (idx + slice_count - 1) / mi_page_map_entries_per_commit_bit; + for (size_t i = commit_bit_idx_lo; i <= commit_bit_idx_hi; i++) { // per bit to avoid crossing over bitmap chunks + if (mi_bitmap_is_clearN(&mi_page_map_commit, i, 1)) { + // this may race, in which case we do multiple commits (which is ok) + if (!mi_page_map_all_committed) { bool is_zero; uint8_t* const start = _mi_page_map + (i*mi_page_map_entries_per_commit_bit); const size_t size = mi_page_map_entries_per_commit_bit; _mi_os_commit(start, size, &is_zero); - if (!is_zero && !mi_page_map_memid.initially_zero) { _mi_memzero(start,size); } - mi_bitmap_set(&mi_page_map_commit, i); + if (!is_zero && !mi_page_map_memid.initially_zero) { _mi_memzero(start, size); } } + mi_bitmap_set(&mi_page_map_commit, i); } - #if MI_DEBUG > 0 - _mi_page_map[idx] = 0; - _mi_page_map[idx+slice_count-1] = 0; - #endif } + #if MI_DEBUG > 0 + _mi_page_map[idx] = 0; + _mi_page_map[idx+slice_count-1] = 0; + #endif } static size_t mi_page_map_get_idx(mi_page_t* page, uint8_t** page_start, size_t* slice_count) {