NFC: introduce SlabNext type for intra-small-slab free pointers
Mostly cosmetic, but eliminates some void*-s and makes intention clearer.
This commit is contained in:
committed by
Matthew Parkinson
parent
db0ca64ff3
commit
49fefc3f83
@@ -743,7 +743,7 @@ namespace snmalloc
|
|||||||
while (pointer_align_up(bp, SLAB_SIZE) != bp)
|
while (pointer_align_up(bp, SLAB_SIZE) != bp)
|
||||||
{
|
{
|
||||||
Slab::alloc_new_list(bp, ffl, rsize);
|
Slab::alloc_new_list(bp, ffl, rsize);
|
||||||
void* prev = ffl.value;
|
SlabNext* prev = ffl.value;
|
||||||
while (prev != nullptr)
|
while (prev != nullptr)
|
||||||
{
|
{
|
||||||
auto n = Metaslab::follow_next(prev);
|
auto n = Metaslab::follow_next(prev);
|
||||||
@@ -1027,7 +1027,7 @@ namespace snmalloc
|
|||||||
{
|
{
|
||||||
SNMALLOC_ASSUME(sizeclass < NUM_SMALL_CLASSES);
|
SNMALLOC_ASSUME(sizeclass < NUM_SMALL_CLASSES);
|
||||||
auto& fl = small_fast_free_lists[sizeclass];
|
auto& fl = small_fast_free_lists[sizeclass];
|
||||||
void* head = fl.value;
|
SlabNext* head = fl.value;
|
||||||
if (likely(head != nullptr))
|
if (likely(head != nullptr))
|
||||||
{
|
{
|
||||||
stats().alloc_request(size);
|
stats().alloc_request(size);
|
||||||
@@ -1148,7 +1148,8 @@ namespace snmalloc
|
|||||||
SNMALLOC_ASSERT(ffl.value == nullptr);
|
SNMALLOC_ASSERT(ffl.value == nullptr);
|
||||||
Slab::alloc_new_list(bp, ffl, rsize);
|
Slab::alloc_new_list(bp, ffl, rsize);
|
||||||
|
|
||||||
void* p = remove_cache_friendly_offset(ffl.value, sizeclass);
|
SlabNext* p = static_cast<SlabNext*>(
|
||||||
|
remove_cache_friendly_offset(ffl.value, sizeclass));
|
||||||
ffl.value = Metaslab::follow_next(p);
|
ffl.value = Metaslab::follow_next(p);
|
||||||
|
|
||||||
if constexpr (zero_mem == YesZero)
|
if constexpr (zero_mem == YesZero)
|
||||||
@@ -1171,8 +1172,8 @@ namespace snmalloc
|
|||||||
Slab* slab = alloc_slab<allow_reserve>(sizeclass);
|
Slab* slab = alloc_slab<allow_reserve>(sizeclass);
|
||||||
if (slab == nullptr)
|
if (slab == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
bp =
|
bp = reinterpret_cast<SlabNext*>(
|
||||||
pointer_offset(slab, get_initial_offset(sizeclass, slab->is_short()));
|
pointer_offset(slab, get_initial_offset(sizeclass, slab->is_short())));
|
||||||
|
|
||||||
return small_alloc_build_free_list<zero_mem, allow_reserve>(sizeclass);
|
return small_alloc_build_free_list<zero_mem, allow_reserve>(sizeclass);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,22 @@ namespace snmalloc
|
|||||||
{
|
{
|
||||||
class Slab;
|
class Slab;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free objects within each slab point directly to the next (contrast
|
||||||
|
* SlabLink, which chain different Slabs of the same sizeclass together).
|
||||||
|
*/
|
||||||
|
struct SlabNext
|
||||||
|
{
|
||||||
|
struct SlabNext* next;
|
||||||
|
#ifdef CHECK_CLIENT
|
||||||
|
uintptr_t guard;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
struct FreeListHead
|
struct FreeListHead
|
||||||
{
|
{
|
||||||
// Use a value with bottom bit set for empty list.
|
// Use a value with bottom bit set for empty list.
|
||||||
void* value = nullptr;
|
SlabNext* value = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
using SlabList = CDLLNode;
|
using SlabList = CDLLNode;
|
||||||
@@ -37,7 +49,7 @@ namespace snmalloc
|
|||||||
*
|
*
|
||||||
* The list will be (allocated - needed) long.
|
* The list will be (allocated - needed) long.
|
||||||
*/
|
*/
|
||||||
void* head = nullptr;
|
SlabNext* head = nullptr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How many entries are not in the free list of slab, i.e.
|
* How many entries are not in the free list of slab, i.e.
|
||||||
@@ -97,31 +109,30 @@ namespace snmalloc
|
|||||||
|
|
||||||
/// Store next pointer in a block. In Debug using magic value to detect some
|
/// Store next pointer in a block. In Debug using magic value to detect some
|
||||||
/// simple corruptions.
|
/// simple corruptions.
|
||||||
static SNMALLOC_FAST_PATH void store_next(void* p, void* head)
|
static SNMALLOC_FAST_PATH void store_next(SlabNext* p, SlabNext* head)
|
||||||
{
|
{
|
||||||
*static_cast<void**>(p) = head;
|
p->next = head;
|
||||||
#if defined(CHECK_CLIENT)
|
#if defined(CHECK_CLIENT)
|
||||||
if constexpr (aal_supports<IntegerPointers>)
|
if constexpr (aal_supports<IntegerPointers>)
|
||||||
{
|
{
|
||||||
*(static_cast<uintptr_t*>(p) + 1) = address_cast(head) ^ POISON;
|
p->guard = address_cast(head) ^ POISON;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Accessor function for the next pointer in a block.
|
/// Accessor function for the next pointer in a block.
|
||||||
/// In Debug checks for simple corruptions.
|
/// In Debug checks for simple corruptions.
|
||||||
static SNMALLOC_FAST_PATH void* follow_next(void* node)
|
static SNMALLOC_FAST_PATH SlabNext* follow_next(SlabNext* node)
|
||||||
{
|
{
|
||||||
#if defined(CHECK_CLIENT)
|
#if defined(CHECK_CLIENT)
|
||||||
if constexpr (aal_supports<IntegerPointers>)
|
if constexpr (aal_supports<IntegerPointers>)
|
||||||
{
|
{
|
||||||
uintptr_t next = *static_cast<uintptr_t*>(node);
|
uintptr_t next = address_cast(node->next);
|
||||||
uintptr_t chk = *(static_cast<uintptr_t*>(node) + 1);
|
if ((next ^ node->guard) != POISON)
|
||||||
if ((next ^ chk) != POISON)
|
|
||||||
error("Detected memory corruption. Use-after-free.");
|
error("Detected memory corruption. Use-after-free.");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return *static_cast<void**>(node);
|
return node->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool valid_head()
|
bool valid_head()
|
||||||
@@ -166,9 +177,9 @@ namespace snmalloc
|
|||||||
debug_slab_invariant(slab);
|
debug_slab_invariant(slab);
|
||||||
|
|
||||||
// Use first element as the allocation
|
// Use first element as the allocation
|
||||||
void* p = head;
|
SlabNext* h = head;
|
||||||
// Put the rest in allocators small_class fast free list.
|
// Put the rest in allocators small_class fast free list.
|
||||||
fast_free_list.value = Metaslab::follow_next(p);
|
fast_free_list.value = Metaslab::follow_next(h);
|
||||||
head = nullptr;
|
head = nullptr;
|
||||||
|
|
||||||
// Treat stealing the free list as allocating it all.
|
// Treat stealing the free list as allocating it all.
|
||||||
@@ -176,7 +187,7 @@ namespace snmalloc
|
|||||||
remove();
|
remove();
|
||||||
set_full();
|
set_full();
|
||||||
|
|
||||||
p = remove_cache_friendly_offset(p, sizeclass);
|
void* p = remove_cache_friendly_offset(h, sizeclass);
|
||||||
SNMALLOC_ASSERT(is_start_of_object(p));
|
SNMALLOC_ASSERT(is_start_of_object(p));
|
||||||
|
|
||||||
debug_slab_invariant(slab);
|
debug_slab_invariant(slab);
|
||||||
@@ -208,8 +219,8 @@ namespace snmalloc
|
|||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
void* curr = head;
|
SlabNext* curr = head;
|
||||||
void* curr_slow = head;
|
SlabNext* curr_slow = head;
|
||||||
bool both = false;
|
bool both = false;
|
||||||
while (curr != nullptr)
|
while (curr != nullptr)
|
||||||
{
|
{
|
||||||
@@ -264,7 +275,7 @@ namespace snmalloc
|
|||||||
UNUSED(length);
|
UNUSED(length);
|
||||||
|
|
||||||
// Walk bump-free-list-segment accounting for unused space
|
// Walk bump-free-list-segment accounting for unused space
|
||||||
void* curr = head;
|
SlabNext* curr = head;
|
||||||
while (curr != nullptr)
|
while (curr != nullptr)
|
||||||
{
|
{
|
||||||
// Check we are looking at a correctly aligned block
|
// Check we are looking at a correctly aligned block
|
||||||
|
|||||||
@@ -29,7 +29,9 @@ namespace snmalloc
|
|||||||
static SNMALLOC_FAST_PATH void
|
static SNMALLOC_FAST_PATH void
|
||||||
alloc_new_list(void*& bumpptr, FreeListHead& fast_free_list, size_t rsize)
|
alloc_new_list(void*& bumpptr, FreeListHead& fast_free_list, size_t rsize)
|
||||||
{
|
{
|
||||||
fast_free_list.value = bumpptr;
|
auto snbumpptr = static_cast<SlabNext*>(bumpptr);
|
||||||
|
fast_free_list.value = snbumpptr;
|
||||||
|
|
||||||
void* newbumpptr = pointer_offset(bumpptr, rsize);
|
void* newbumpptr = pointer_offset(bumpptr, rsize);
|
||||||
void* slab_end = pointer_align_up<SLAB_SIZE>(newbumpptr);
|
void* slab_end = pointer_align_up<SLAB_SIZE>(newbumpptr);
|
||||||
void* slab_end2 =
|
void* slab_end2 =
|
||||||
@@ -39,12 +41,14 @@ namespace snmalloc
|
|||||||
|
|
||||||
while (newbumpptr < slab_end)
|
while (newbumpptr < slab_end)
|
||||||
{
|
{
|
||||||
Metaslab::store_next(bumpptr, newbumpptr);
|
auto newsnbumpptr = static_cast<SlabNext*>(newbumpptr);
|
||||||
|
Metaslab::store_next(snbumpptr, newsnbumpptr);
|
||||||
|
snbumpptr = newsnbumpptr;
|
||||||
bumpptr = newbumpptr;
|
bumpptr = newbumpptr;
|
||||||
newbumpptr = pointer_offset(bumpptr, rsize);
|
newbumpptr = pointer_offset(bumpptr, rsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
Metaslab::store_next(bumpptr, nullptr);
|
Metaslab::store_next(snbumpptr, nullptr);
|
||||||
bumpptr = newbumpptr;
|
bumpptr = newbumpptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,14 +67,16 @@ namespace snmalloc
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Update the head and the next pointer in the free list.
|
// Update the head and the next pointer in the free list.
|
||||||
void* head = meta.head;
|
SlabNext* head = meta.head;
|
||||||
|
|
||||||
|
SlabNext* psn = static_cast<SlabNext*>(p);
|
||||||
|
|
||||||
// Set the head to the memory being deallocated.
|
// Set the head to the memory being deallocated.
|
||||||
meta.head = p;
|
meta.head = psn;
|
||||||
SNMALLOC_ASSERT(meta.valid_head());
|
SNMALLOC_ASSERT(meta.valid_head());
|
||||||
|
|
||||||
// Set the next pointer to the previous head.
|
// Set the next pointer to the previous head.
|
||||||
Metaslab::store_next(p, head);
|
Metaslab::store_next(psn, head);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -97,8 +103,9 @@ namespace snmalloc
|
|||||||
return super->dealloc_slab(this);
|
return super->dealloc_slab(this);
|
||||||
}
|
}
|
||||||
SNMALLOC_ASSERT(meta.head == nullptr);
|
SNMALLOC_ASSERT(meta.head == nullptr);
|
||||||
meta.head = p;
|
SlabNext* psn = static_cast<SlabNext*>(p);
|
||||||
Metaslab::store_next(p, nullptr);
|
meta.head = psn;
|
||||||
|
Metaslab::store_next(psn, nullptr);
|
||||||
meta.needed = meta.allocated - 1;
|
meta.needed = meta.allocated - 1;
|
||||||
|
|
||||||
// Push on the list of slabs for this sizeclass.
|
// Push on the list of slabs for this sizeclass.
|
||||||
|
|||||||
Reference in New Issue
Block a user