Pass continuations for success and failure cases (#788)

This PR provides a templated parameter to the allocation routines. This can be used to add special behaviour in
both the successful allocation behaviour, and in the failing
to allocate cases.

The intent of this is two enable two future features
* set_new_handler - so that the failure case doesn't just set ENOMEM, and return nullptr.  But can handle both the Windows and C++ versions of (_)set_new_handler.
* The success handler can be used to add checking, zeroing and in the future storing precise size information in metadata for each allocation.
This commit is contained in:
Matthew Parkinson
2025-07-03 20:05:52 +01:00
committed by GitHub
parent 012138e29f
commit d4c7e01cd7
14 changed files with 145 additions and 119 deletions

View File

@@ -91,7 +91,7 @@ int main()
{
static const size_t sz = 1024 * 1024;
errno = 0;
void* olarge = alloc->alloc<YesZero>(sz);
void* olarge = alloc->alloc<Zero>(sz);
int err = errno;
SNMALLOC_CHECK(alarge == address_cast(olarge));

View File

@@ -47,14 +47,14 @@ void check_calloc(void* p, size_t size)
void calloc1(size_t size)
{
void* r = snmalloc::alloc<snmalloc::ZeroMem::YesZero>(size);
void* r = snmalloc::alloc<snmalloc::Zero>(size);
check_calloc(r, size);
snmalloc::dealloc(r);
}
void calloc2(size_t size)
{
void* r = snmalloc::alloc<snmalloc::ZeroMem::YesZero>(size);
void* r = snmalloc::alloc<snmalloc::Zero>(size);
check_calloc(r, size);
snmalloc::dealloc(r, size);
}

View File

@@ -173,10 +173,12 @@ namespace
size * 2);
EXPECT(
ptr[size] == 0,
"Memory not zero initialised for {} byte reallocation from {} "
"Memory not zero initialised for {} byte reallocation from {} with "
"align {}"
"byte allocation",
size * 2,
size);
size,
align);
// The second time we run this test, we if we're allocating from a free
// list then we will reuse this, so make sure it requires explicit
// zeroing.

View File

@@ -178,7 +178,7 @@ void test_calloc()
memset(p, 0xFF, size);
snmalloc::dealloc(p, size);
p = snmalloc::alloc<YesZero>(size);
p = snmalloc::alloc<Zero>(size);
for (size_t i = 0; i < size; i++)
{
@@ -417,7 +417,7 @@ void test_calloc_16M()
// sizes >= 16M use large_alloc
const size_t size = 16'000'000;
void* p1 = snmalloc::alloc<YesZero>(size);
void* p1 = snmalloc::alloc<Zero>(size);
SNMALLOC_CHECK(snmalloc::alloc_size(snmalloc::external_pointer(p1)) >= size);
snmalloc::dealloc(p1);
}
@@ -430,7 +430,7 @@ void test_calloc_large_bug()
// not a multiple of page size.
const size_t size = (MAX_SMALL_SIZECLASS_SIZE << 3) - 7;
void* p1 = snmalloc::alloc<YesZero>(size);
void* p1 = snmalloc::alloc<Zero>(size);
SNMALLOC_CHECK(snmalloc::alloc_size(snmalloc::external_pointer(p1)) >= size);
snmalloc::dealloc(p1);
}

View File

@@ -59,7 +59,7 @@ void check_calloc(void* p, size_t size)
void calloc1(size_t size)
{
trigger_teardown();
void* r = snmalloc::alloc<snmalloc::ZeroMem::YesZero>(size);
void* r = snmalloc::alloc<snmalloc::Zero>(size);
check_calloc(r, size);
snmalloc::dealloc(r);
}
@@ -67,7 +67,7 @@ void calloc1(size_t size)
void calloc2(size_t size)
{
trigger_teardown();
void* r = snmalloc::alloc<snmalloc::ZeroMem::YesZero>(size);
void* r = snmalloc::alloc<snmalloc::Zero>(size);
check_calloc(r, size);
snmalloc::dealloc(r, size);
}

View File

@@ -5,20 +5,21 @@
using namespace snmalloc;
template<ZeroMem zero_mem>
template<typename Conts>
void test_alloc_dealloc(size_t count, size_t size, bool write)
{
{
MeasureTime m;
m << "Count: " << std::setw(6) << count << ", Size: " << std::setw(6)
<< size << ", ZeroMem: " << (zero_mem == YesZero) << ", Write: " << write;
<< size
<< ", ZeroMem: " << std::is_same_v<Conts, Zero> << ", Write: " << write;
std::unordered_set<void*> set;
// alloc 1.5x objects
for (size_t i = 0; i < ((count * 3) / 2); i++)
{
void* p = snmalloc::alloc<zero_mem>(size);
void* p = snmalloc::alloc<Conts>(size);
SNMALLOC_CHECK(set.find(p) == set.end());
if (write)
@@ -40,7 +41,7 @@ void test_alloc_dealloc(size_t count, size_t size, bool write)
// alloc 1x objects
for (size_t i = 0; i < count; i++)
{
void* p = snmalloc::alloc<zero_mem>(size);
void* p = snmalloc::alloc<Conts>(size);
SNMALLOC_CHECK(set.find(p) == set.end());
if (write)
@@ -67,18 +68,18 @@ int main(int, char**)
for (size_t size = 16; size <= 128; size <<= 1)
{
test_alloc_dealloc<NoZero>(1 << 15, size, false);
test_alloc_dealloc<NoZero>(1 << 15, size, true);
test_alloc_dealloc<YesZero>(1 << 15, size, false);
test_alloc_dealloc<YesZero>(1 << 15, size, true);
test_alloc_dealloc<Uninit>(1 << 15, size, false);
test_alloc_dealloc<Uninit>(1 << 15, size, true);
test_alloc_dealloc<Zero>(1 << 15, size, false);
test_alloc_dealloc<Zero>(1 << 15, size, true);
}
for (size_t size = 1 << 12; size <= 1 << 17; size <<= 1)
{
test_alloc_dealloc<NoZero>(1 << 10, size, false);
test_alloc_dealloc<NoZero>(1 << 10, size, true);
test_alloc_dealloc<YesZero>(1 << 10, size, false);
test_alloc_dealloc<YesZero>(1 << 10, size, true);
test_alloc_dealloc<Uninit>(1 << 10, size, false);
test_alloc_dealloc<Uninit>(1 << 10, size, true);
test_alloc_dealloc<Zero>(1 << 10, size, false);
test_alloc_dealloc<Zero>(1 << 10, size, true);
}
return 0;