diff --git a/docs/PORTING.md b/docs/PORTING.md index 8e39451..f6c4567 100644 --- a/docs/PORTING.md +++ b/docs/PORTING.md @@ -33,6 +33,15 @@ function may not be required to do anything. If the template parameter is set to `YesZero` then this function is also responsible for ensuring that the newly requested memory is full of zeros. +```c++ +static void notify_using_readonly(void* p, size_t size) noexcept; +``` +Notify the system that the range of memory from `p` to `p` + `size` is now in use +for read-only access. This is currently only requried on platforms that support +`LazyCommit`. +On systems that lazily provide physical memory to virtual mappings, this +function may not be required to do anything. + ```c++ template static void zero(void* p, size_t size) noexcept; diff --git a/src/backend/pagemap.h b/src/backend/pagemap.h index c3e5667..7204162 100644 --- a/src/backend/pagemap.h +++ b/src/backend/pagemap.h @@ -159,7 +159,7 @@ namespace snmalloc #ifdef SNMALLOC_CHECK_CLIENT // Allocate a power of two extra to allow the placement of the // pagemap be difficult to guess. - size_t additional_size = bits::next_pow2(REQUIRED_SIZE) * 2; + size_t additional_size = bits::next_pow2(REQUIRED_SIZE) * 4; size_t request_size = REQUIRED_SIZE + additional_size; #else size_t request_size = REQUIRED_SIZE; @@ -178,6 +178,18 @@ namespace snmalloc size_t offset = get_entropy64() & (additional_size - sizeof(T)); auto new_body = reinterpret_cast(pointer_offset(new_body_untyped, offset)); + + if constexpr (pal_supports) + { + void* start_page = pointer_align_down(new_body); + void* end_page = pointer_align_up( + pointer_offset(new_body, REQUIRED_SIZE)); + // Only commit readonly memory for this range, if the platform supports + // lazy commit. Otherwise, this would be a lot of memory to have + // mapped. + PAL::notify_using_readonly( + start_page, pointer_diff(start_page, end_page)); + } #else auto new_body = reinterpret_cast(new_body_untyped); #endif @@ -243,15 +255,10 @@ namespace snmalloc p = p - base; } - // This means external pointer on Windows will be slow. - // TODO: With SNMALLOC_CHECK_CLIENT we should map that region read-only, - // not no-access, but this requires a PAL change. - if constexpr ( - potentially_out_of_range -#ifndef SNMALLOC_CHECK_CLIENT - && !pal_supports -#endif - ) + // If this is potentially_out_of_range, then the pages will not have + // been mapped. With Lazy commit they will at least be mapped read-only + // Note that: this means external pointer on Windows will be slow. + if constexpr (potentially_out_of_range && !pal_supports) { register_range(p, 1); } diff --git a/src/pal/pal_posix.h b/src/pal/pal_posix.h index dd3932b..ff4cd52 100644 --- a/src/pal/pal_posix.h +++ b/src/pal/pal_posix.h @@ -196,7 +196,7 @@ namespace snmalloc * * On POSIX platforms, lazy commit means that this is a no-op, unless we * are also zeroing the pages in which case we call the platform's `zero` - * function. + * function, or we have initially mapped the pages as PROT_NONE. */ template static void notify_using(void* p, size_t size) noexcept @@ -215,6 +215,24 @@ namespace snmalloc zero(p, size); } + /** + * Notify platform that we will be using these pages for reading. + * + * On POSIX platforms, lazy commit means that this is a no-op, unless + * we have initially mapped the pages as PROT_NONE. + */ + static void notify_using_readonly(void* p, size_t size) noexcept + { + SNMALLOC_ASSERT(is_aligned_block(p, size)); + +#ifdef SNMALLOC_CHECK_CLIENT + mprotect(p, size, PROT_READ); +#else + UNUSED(p); + UNUSED(size); +#endif + } + /** * OS specific function for zeroing memory. *