From 53d9fd2abefe5488f42c89e58038e416ecec4416 Mon Sep 17 00:00:00 2001 From: Matthew Parkinson Date: Tue, 31 May 2022 13:59:42 +0100 Subject: [PATCH] Alter PAGE_SIZE usage (#534) * Sanity check on parameters to large buddy. * Check commit occurs at page granularity * Alter PAGE_SIZE usage Using PAGE_SIZE as the minimum size of the CHUNK means that if this is configured to 2MiB, then there is a gap between MAX_SMALL_SIZECLASS_SIZE, and MIN_CHUNK_SIZE, and thus we can't represent certain sizes, --- src/snmalloc/backend/meta_protected_range.h | 27 ++++++++++++++++--- src/snmalloc/backend/standard_range.h | 9 ++++++- src/snmalloc/backend_helpers/commitrange.h | 10 +++++++ .../backend_helpers/largebuddyrange.h | 6 +++++ src/snmalloc/ds/allocconfig.h | 7 +++-- 5 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/snmalloc/backend/meta_protected_range.h b/src/snmalloc/backend/meta_protected_range.h index 8a8c5fe2..9a16f927 100644 --- a/src/snmalloc/backend/meta_protected_range.h +++ b/src/snmalloc/backend/meta_protected_range.h @@ -40,6 +40,12 @@ namespace snmalloc LogRange<2>, GlobalRange<>>; + static constexpr size_t page_size_bits = + bits::next_pow2_bits_const(PAL::page_size); + + static constexpr size_t max_page_chunk_size_bits = + bits::max(page_size_bits, MIN_CHUNK_BITS); + // Central source of object-range, does not pass back to GlobalR as // that would allow flows from Objects to Meta-data, and thus UAF // would be able to corrupt meta-data. @@ -61,16 +67,31 @@ namespace snmalloc GlobalR, SubRange, // Use SubRange to introduce guard // pages. - LargeBuddyRange, + LargeBuddyRange< + GlobalCacheSizeBits, + bits::BITS - 1, + Pagemap, + page_size_bits>, + CommitRange, + // In case of huge pages, we don't want to give each thread its own huge + // page, so commit in the global range. + LargeBuddyRange< + max_page_chunk_size_bits, + max_page_chunk_size_bits, + Pagemap, + page_size_bits>, LogRange<4>, GlobalRange<>, - CommitRange, StatsRange<>>; // Local caching of object range using ObjectRange = Pipe< CentralObjectRange, - LargeBuddyRange, + LargeBuddyRange< + LocalCacheSizeBits, + LocalCacheSizeBits, + Pagemap, + page_size_bits>, LogRange<5>>; // Local caching of meta-data range diff --git a/src/snmalloc/backend/standard_range.h b/src/snmalloc/backend/standard_range.h index 0feb0aff..b808f4cf 100644 --- a/src/snmalloc/backend/standard_range.h +++ b/src/snmalloc/backend/standard_range.h @@ -41,11 +41,18 @@ namespace snmalloc using Stats = Pipe, StatsRange<>>; private: + static constexpr size_t page_size_bits = + bits::next_pow2_bits_const(PAL::page_size); + // Source for object allocations and metadata // Use buddy allocators to cache locally. using ObjectRange = Pipe< Stats, - LargeBuddyRange, + LargeBuddyRange< + LocalCacheSizeBits, + LocalCacheSizeBits, + Pagemap, + page_size_bits>, SmallBuddyRange<>>; public: diff --git a/src/snmalloc/backend_helpers/commitrange.h b/src/snmalloc/backend_helpers/commitrange.h index 938c2384..11bead47 100644 --- a/src/snmalloc/backend_helpers/commitrange.h +++ b/src/snmalloc/backend_helpers/commitrange.h @@ -25,6 +25,11 @@ namespace snmalloc capptr::Chunk alloc_range(size_t size) { + SNMALLOC_ASSERT_MSG( + (size % PAL::page_size) == 0, + "size ({}) must be a multiple of page size ({})", + size, + PAL::page_size); auto range = parent.alloc_range(size); if (range != nullptr) PAL::template notify_using(range.unsafe_ptr(), size); @@ -33,6 +38,11 @@ namespace snmalloc void dealloc_range(capptr::Chunk base, size_t size) { + SNMALLOC_ASSERT_MSG( + (size % PAL::page_size) == 0, + "size ({}) must be a multiple of page size ({})", + size, + PAL::page_size); PAL::notify_not_using(base.unsafe_ptr(), size); parent.dealloc_range(base, size); } diff --git a/src/snmalloc/backend_helpers/largebuddyrange.h b/src/snmalloc/backend_helpers/largebuddyrange.h index 8f4b7ee6..afeef29f 100644 --- a/src/snmalloc/backend_helpers/largebuddyrange.h +++ b/src/snmalloc/backend_helpers/largebuddyrange.h @@ -193,6 +193,12 @@ namespace snmalloc { using ContainsParent::parent; + static_assert( + REFILL_SIZE_BITS <= MAX_SIZE_BITS, "REFILL_SIZE_BITS > MAX_SIZE_BITS"); + static_assert( + MIN_REFILL_SIZE_BITS <= REFILL_SIZE_BITS, + "MIN_REFILL_SIZE_BITS > REFILL_SIZE_BITS"); + /** * Maximum size of a refill */ diff --git a/src/snmalloc/ds/allocconfig.h b/src/snmalloc/ds/allocconfig.h index b3e789e5..51d5b415 100644 --- a/src/snmalloc/ds/allocconfig.h +++ b/src/snmalloc/ds/allocconfig.h @@ -26,8 +26,7 @@ namespace snmalloc static constexpr size_t MIN_ALLOC_BITS = bits::ctz_const(MIN_ALLOC_SIZE); // Minimum slab size. - static constexpr size_t MIN_CHUNK_BITS = bits::max( - static_cast(14), bits::next_pow2_bits_const(OS_PAGE_SIZE)); + static constexpr size_t MIN_CHUNK_BITS = static_cast(14); static constexpr size_t MIN_CHUNK_SIZE = bits::one_at_bit(MIN_CHUNK_BITS); // Minimum number of objects on a slab @@ -42,6 +41,10 @@ namespace snmalloc static constexpr size_t MAX_SMALL_SIZECLASS_SIZE = bits::one_at_bit(MAX_SMALL_SIZECLASS_BITS); + static_assert( + MAX_SMALL_SIZECLASS_SIZE >= MIN_CHUNK_SIZE, + "Large sizes need to be representable by as a multiple of MIN_CHUNK_SIZE"); + // Number of slots for remote deallocation. static constexpr size_t REMOTE_SLOT_BITS = 8; static constexpr size_t REMOTE_SLOTS = 1 << REMOTE_SLOT_BITS;