SP: LargeAlloc return CBChunk & chase consequences

Even if we opt not to bound these pointers internally (if they aren't headed out
to the user program or we later derive bounded pointers), they should still be
annotated as something other than CBArena, ensuring that we do not attempt to
use them for general amplification.
This commit is contained in:
Nathaniel Filardo
2021-04-01 13:20:17 +01:00
committed by Nathaniel Wesley Filardo
parent 54fec3821f
commit f7821e11eb
10 changed files with 175 additions and 126 deletions

View File

@@ -35,7 +35,7 @@ namespace snmalloc
* bits::BITS is used for simplicity, we do not use below the pointer size,
* and large entries will be unlikely to be supported by the platform.
*/
std::array<std::array<CapPtr<void, CBArena>, 2>, bits::BITS> ranges = {};
std::array<std::array<CapPtr<void, CBChunk>, 2>, bits::BITS> ranges = {};
/**
* This is infrequently used code, a spin lock simplifies the code
@@ -46,7 +46,7 @@ namespace snmalloc
/**
* Checks a block satisfies its invariant.
*/
inline void check_block(CapPtr<void, CBArena> base, size_t align_bits)
inline void check_block(CapPtr<void, CBChunk> base, size_t align_bits)
{
SNMALLOC_ASSERT(
base == pointer_align_up(base, bits::one_at_bit(align_bits)));
@@ -59,7 +59,7 @@ namespace snmalloc
/**
* Adds a block to `ranges`.
*/
void add_block(size_t align_bits, CapPtr<void, CBArena> base)
void add_block(size_t align_bits, CapPtr<void, CBChunk> base)
{
check_block(base, align_bits);
SNMALLOC_ASSERT(align_bits < 64);
@@ -74,7 +74,7 @@ namespace snmalloc
{
// Add to linked list.
commit_block(base, sizeof(void*));
*(base.template as_static<CapPtr<void, CBArena>>().unsafe_capptr) =
*(base.template as_static<CapPtr<void, CBChunk>>().unsafe_capptr) =
ranges[align_bits][1];
check_block(ranges[align_bits][1], align_bits);
}
@@ -88,9 +88,9 @@ namespace snmalloc
* Find a block of the correct size. May split larger blocks
* to satisfy this request.
*/
CapPtr<void, CBArena> remove_block(size_t align_bits)
CapPtr<void, CBChunk> remove_block(size_t align_bits)
{
CapPtr<void, CBArena> first = ranges[align_bits][0];
CapPtr<void, CBChunk> first = ranges[align_bits][0];
if (first == nullptr)
{
if (align_bits == (bits::BITS - 1))
@@ -100,7 +100,7 @@ namespace snmalloc
}
// Look for larger block and split up recursively
CapPtr<void, CBArena> bigger = remove_block(align_bits + 1);
CapPtr<void, CBChunk> bigger = remove_block(align_bits + 1);
if (bigger != nullptr)
{
auto left_over = pointer_offset(bigger, bits::one_at_bit(align_bits));
@@ -111,12 +111,12 @@ namespace snmalloc
return bigger;
}
CapPtr<void, CBArena> second = ranges[align_bits][1];
CapPtr<void, CBChunk> second = ranges[align_bits][1];
if (second != nullptr)
{
commit_block(second, sizeof(void*));
auto psecond =
second.template as_static<CapPtr<void, CBArena>>().unsafe_capptr;
second.template as_static<CapPtr<void, CBChunk>>().unsafe_capptr;
auto next = *psecond;
ranges[align_bits][1] = next;
// Zero memory. Client assumes memory contains only zeros.
@@ -135,7 +135,7 @@ namespace snmalloc
* Add a range of memory to the address space.
* Divides blocks into power of two sizes with natural alignment
*/
void add_range(CapPtr<void, CBArena> base, size_t length)
void add_range(CapPtr<void, CBChunk> base, size_t length)
{
// Find the minimum set of maximally aligned blocks in this range.
// Each block's alignment and size are equal.
@@ -157,7 +157,7 @@ namespace snmalloc
/**
* Commit a block of memory
*/
void commit_block(CapPtr<void, CBArena> base, size_t size)
void commit_block(CapPtr<void, CBChunk> base, size_t size)
{
// Rounding required for sub-page allocations.
auto page_start = pointer_align_down<OS_PAGE_SIZE, char>(base);
@@ -180,7 +180,7 @@ namespace snmalloc
* arena_map for use in subsequent amplification.
*/
template<bool committed>
CapPtr<void, CBArena> reserve(size_t size, ArenaMap& arena_map)
CapPtr<void, CBChunk> reserve(size_t size, ArenaMap& arena_map)
{
SNMALLOC_ASSERT(bits::is_pow2(size));
SNMALLOC_ASSERT(size >= sizeof(void*));
@@ -194,18 +194,18 @@ namespace snmalloc
pal_supports<AlignedAllocation, PAL> && !aal_supports<StrictProvenance>)
{
if (size >= PAL::minimum_alloc_size)
return CapPtr<void, CBArena>(
return CapPtr<void, CBChunk>(
PAL::template reserve_aligned<committed>(size));
}
CapPtr<void, CBArena> res;
CapPtr<void, CBChunk> res;
{
FlagLock lock(spin_lock);
res = remove_block(bits::next_pow2_bits(size));
if (res == nullptr)
{
// Allocation failed ask OS for more memory
CapPtr<void, CBArena> block = nullptr;
CapPtr<void, CBChunk> block = nullptr;
size_t block_size = 0;
if constexpr (pal_supports<AlignedAllocation, PAL>)
{
@@ -233,7 +233,10 @@ namespace snmalloc
void* block_raw = PAL::template reserve_aligned<false>(block_size);
block = CapPtr<void, CBArena>(block_raw);
// It's a bit of a lie to convert without applying bounds, but the
// platform will have bounded block for us and it's better that the
// rest of our internals expect CBChunk bounds.
block = CapPtr<void, CBChunk>(block_raw);
if constexpr (aal_supports<StrictProvenance>)
{
@@ -254,7 +257,7 @@ namespace snmalloc
// the PAL, and this could lead to suprious OOM. This is
// particularly bad if the PAL gives all the memory on first call.
auto block_and_size = PAL::reserve_at_least(size * 2);
block = CapPtr<void, CBArena>(block_and_size.first);
block = CapPtr<void, CBChunk>(block_and_size.first);
block_size = block_and_size.second;
// Ensure block is pointer aligned.
@@ -294,7 +297,7 @@ namespace snmalloc
* used, by smaller objects.
*/
template<bool committed>
CapPtr<void, CBArena>
CapPtr<void, CBChunk>
reserve_with_left_over(size_t size, ArenaMap& arena_map)
{
SNMALLOC_ASSERT(size >= sizeof(void*));
@@ -330,7 +333,7 @@ namespace snmalloc
* Constructor that pre-initialises the address-space manager with a region
* of memory.
*/
AddressSpaceManager(CapPtr<void, CBArena> base, size_t length)
AddressSpaceManager(CapPtr<void, CBChunk> base, size_t length)
{
add_range(base, length);
}