initial working guarded pages
This commit is contained in:
75
src/alloc.c
75
src/alloc.c
@@ -40,9 +40,9 @@ extern inline void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_
|
||||
page->free = mi_block_next(page, block);
|
||||
page->used++;
|
||||
mi_assert_internal(page->free == NULL || _mi_ptr_page(page->free) == page);
|
||||
mi_assert_internal(_mi_is_aligned(block, MI_MAX_ALIGN_SIZE));
|
||||
mi_assert_internal(page->block_size < MI_MAX_ALIGN_SIZE || _mi_is_aligned(block, MI_MAX_ALIGN_SIZE));
|
||||
#if MI_DEBUG>3
|
||||
if (page->free_is_zero) {
|
||||
if (page->free_is_zero && size > sizeof(*block)) {
|
||||
mi_assert_expensive(mi_mem_is_zero(block+1,size - sizeof(*block)));
|
||||
}
|
||||
#endif
|
||||
@@ -56,6 +56,7 @@ extern inline void* _mi_page_malloc_zero(mi_heap_t* heap, mi_page_t* page, size_
|
||||
if mi_unlikely(zero) {
|
||||
mi_assert_internal(page->block_size != 0); // do not call with zero'ing for huge blocks (see _mi_malloc_generic)
|
||||
mi_assert_internal(page->block_size >= MI_PADDING_SIZE);
|
||||
mi_assert_internal(!mi_page_is_huge(page));
|
||||
if (page->free_is_zero) {
|
||||
block->next = 0;
|
||||
mi_track_mem_defined(block, page->block_size - MI_PADDING_SIZE);
|
||||
@@ -114,6 +115,11 @@ extern void* _mi_page_malloc_zeroed(mi_heap_t* heap, mi_page_t* page, size_t siz
|
||||
return _mi_page_malloc_zero(heap,page,size,true);
|
||||
}
|
||||
|
||||
#if MI_DEBUG_GUARDED
|
||||
// forward declaration
|
||||
static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept;
|
||||
#endif
|
||||
|
||||
static inline mi_decl_restrict void* mi_heap_malloc_small_zero(mi_heap_t* heap, size_t size, bool zero) mi_attr_noexcept {
|
||||
mi_assert(heap != NULL);
|
||||
#if MI_DEBUG
|
||||
@@ -121,9 +127,14 @@ static inline mi_decl_restrict void* mi_heap_malloc_small_zero(mi_heap_t* heap,
|
||||
mi_assert(heap->thread_id == 0 || heap->thread_id == tid); // heaps are thread local
|
||||
#endif
|
||||
mi_assert(size <= MI_SMALL_SIZE_MAX);
|
||||
#if (MI_PADDING)
|
||||
#if (MI_PADDING || MI_DEBUG_GUARDED)
|
||||
if (size == 0) { size = sizeof(void*); }
|
||||
#endif
|
||||
#if MI_DEBUG_GUARDED
|
||||
if (size >= _mi_option_get_fast(mi_option_debug_guarded_min) && size <= _mi_option_get_fast(mi_option_debug_guarded_max)) {
|
||||
return mi_heap_malloc_guarded(heap, size, zero, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
mi_page_t* page = _mi_heap_get_free_small_page(heap, size + MI_PADDING_SIZE);
|
||||
void* const p = _mi_page_malloc_zero(heap, page, size + MI_PADDING_SIZE, zero);
|
||||
@@ -158,6 +169,14 @@ extern inline void* _mi_heap_malloc_zero_ex(mi_heap_t* heap, size_t size, bool z
|
||||
mi_assert_internal(huge_alignment == 0);
|
||||
return mi_heap_malloc_small_zero(heap, size, zero);
|
||||
}
|
||||
#if MI_DEBUG_GUARDED
|
||||
else if ( huge_alignment == 0 && // guarded pages do not work with huge aligments at the moment
|
||||
((size >= _mi_option_get_fast(mi_option_debug_guarded_min) && size <= _mi_option_get_fast(mi_option_debug_guarded_max))
|
||||
|| ((size & (_mi_os_page_size()-1)) == 0)) ) // page-size multiple are always guarded so we can have a correct `mi_usable_size`.
|
||||
{
|
||||
return mi_heap_malloc_guarded(heap, size, zero, 0);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
mi_assert(heap!=NULL);
|
||||
mi_assert(heap->thread_id == 0 || heap->thread_id == _mi_thread_id()); // heaps are thread local
|
||||
@@ -578,6 +597,56 @@ mi_decl_nodiscard void* mi_new_reallocn(void* p, size_t newcount, size_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
#if MI_DEBUG_GUARDED
|
||||
static mi_decl_restrict void* mi_heap_malloc_guarded(mi_heap_t* heap, size_t size, bool zero, size_t huge_alignment) mi_attr_noexcept
|
||||
{
|
||||
#if defined(MI_PADDING_SIZE)
|
||||
mi_assert(MI_PADDING_SIZE==0);
|
||||
#endif
|
||||
// allocate multiple of page size ending in a guard page
|
||||
const size_t bsize = _mi_align_up(size, MI_MAX_ALIGN_SIZE); // ensure minimal alignment requirement
|
||||
const size_t psize = _mi_os_page_size();
|
||||
const size_t gsize = _mi_align_up(bsize + psize, psize);
|
||||
void* const base = _mi_malloc_generic(heap, gsize, zero, huge_alignment);
|
||||
if (base==NULL) return NULL;
|
||||
mi_page_t* page = _mi_ptr_page(base);
|
||||
mi_segment_t* segment = _mi_page_segment(page);
|
||||
|
||||
const size_t fullsize = mi_page_block_size(page); // must use `block_size` to match `mi_free_local`
|
||||
void* const gpage = (uint8_t*)base + (fullsize - psize);
|
||||
mi_assert_internal(_mi_is_aligned(gpage, psize));
|
||||
void* const p = (uint8_t*)base + (fullsize - psize - bsize);
|
||||
mi_assert_internal(p >= base);
|
||||
|
||||
// set page flags
|
||||
if (p > base) { mi_page_set_has_aligned(page, true); }
|
||||
|
||||
// set guard page
|
||||
if (segment->allow_decommit) {
|
||||
mi_page_set_has_guarded(page, true);
|
||||
_mi_os_protect(gpage, psize);
|
||||
}
|
||||
else {
|
||||
_mi_warning_message("unable to set a guard page behind an object due to pinned memory (large OS pages?) (object %p of size %zu)\n", p, size);
|
||||
}
|
||||
|
||||
// stats
|
||||
mi_track_malloc(p, size, zero);
|
||||
#if MI_STAT>1
|
||||
if (p != NULL) {
|
||||
if (!mi_heap_is_initialized(heap)) { heap = mi_prim_get_default_heap(); }
|
||||
mi_heap_stat_increase(heap, malloc, mi_usable_size(p));
|
||||
}
|
||||
#endif
|
||||
#if MI_DEBUG>3
|
||||
if (p != NULL && zero) {
|
||||
mi_assert_expensive(mi_mem_is_zero(p, size));
|
||||
}
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------
|
||||
// ensure explicit external inline definitions are emitted!
|
||||
// ------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user