From ec288b7d3301b65a48a5a13d6a43b53afbc61630 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 5 Dec 2021 08:49:59 +0000 Subject: [PATCH] override add OpenBSD's malloc_conceal API proposal. first step: templatization of PALs, type not triggered yet. --- src/backend/globalconfig.h | 12 ++-- src/mem/chunkallocator.h | 2 +- src/mem/entropy.h | 2 +- src/mem/scopedalloc.h | 4 +- src/mem/sizeclasstable.h | 2 +- src/mem/threadalloc.h | 7 ++- src/override/malloc.cc | 36 +++++++++++ src/override/memcpy.cc | 2 +- src/override/override.h | 2 +- src/pal/pal.h | 14 +++-- src/pal/pal_consts.h | 12 ++++ src/pal/pal_linux.h | 22 ++++++- src/snmalloc.h | 2 +- src/test/func/domestication/domestication.cc | 10 +-- src/test/func/fixed_region/fixed_region.cc | 6 +- src/test/func/malloc/malloc.cc | 61 ++++++++++++++++--- src/test/func/memory/memory.cc | 2 +- src/test/func/pagemap/pagemap.cc | 10 +-- src/test/func/pool/pool.cc | 6 +- src/test/func/sandbox/sandbox.cc | 4 +- src/test/func/statistics/stats.cc | 2 +- .../thread_alloc_external.cc | 12 ++-- src/test/func/two_alloc_types/alloc1.cc | 4 +- .../perf/external_pointer/externalpointer.cc | 6 +- 24 files changed, 180 insertions(+), 62 deletions(-) diff --git a/src/backend/globalconfig.h b/src/backend/globalconfig.h index b1243a511..736ecf204 100644 --- a/src/backend/globalconfig.h +++ b/src/backend/globalconfig.h @@ -29,13 +29,14 @@ namespace snmalloc * from the operating system and expects to manage memory anywhere in the * address space. */ - class Globals final : public BackendAllocator + template + class GlobalsConfig final : public BackendAllocator, false> { public: - using GlobalPoolState = PoolState>; + using GlobalPoolState = PoolState>>; private: - using Backend = BackendAllocator; + using Backend = BackendAllocator, false>; SNMALLOC_REQUIRE_CONSTINIT inline static ChunkAllocatorState chunk_allocator_state; @@ -76,7 +77,7 @@ namespace snmalloc return; LocalEntropy entropy; - entropy.init(); + entropy.init>(); // Initialise key for remote deallocation lists key_global = FreeListKey(entropy.get_free_list_key()); @@ -104,4 +105,7 @@ namespace snmalloc snmalloc::register_clean_up(); } }; + + using Globals = GlobalsConfig; + using GlobalsNd = GlobalsConfig; } // namespace snmalloc diff --git a/src/mem/chunkallocator.h b/src/mem/chunkallocator.h index 9f4de928a..9a5e3ad00 100644 --- a/src/mem/chunkallocator.h +++ b/src/mem/chunkallocator.h @@ -30,7 +30,7 @@ namespace snmalloc /** * How many slab sizes that can be provided. */ - constexpr size_t NUM_SLAB_SIZES = Pal::address_bits - MIN_CHUNK_BITS; + constexpr size_t NUM_SLAB_SIZES = Pal::address_bits - MIN_CHUNK_BITS; /** * Used to ensure the per slab meta data is large enough for both use cases. diff --git a/src/mem/entropy.h b/src/mem/entropy.h index 7f1491950..37c15fa66 100644 --- a/src/mem/entropy.h +++ b/src/mem/entropy.h @@ -21,7 +21,7 @@ namespace snmalloc std::enable_if_t, uint64_t> get_entropy64() { #ifdef SNMALLOC_PLATFORM_HAS_GETENTROPY - return DefaultPal::get_entropy64(); + return DefaultPal::get_entropy64(); #else std::random_device rd; uint64_t a = rd(); diff --git a/src/mem/scopedalloc.h b/src/mem/scopedalloc.h index 345635a70..24b69308b 100644 --- a/src/mem/scopedalloc.h +++ b/src/mem/scopedalloc.h @@ -20,7 +20,7 @@ namespace snmalloc /** * The allocator that this wrapper will use. */ - Alloc alloc; + Alloc<> alloc; /** * Constructor. Claims an allocator from the global pool @@ -66,7 +66,7 @@ namespace snmalloc * Arrow operator, allows methods exposed by `Alloc` to be called on the * wrapper. */ - Alloc* operator->() + Alloc<>* operator->() { return &alloc; } diff --git a/src/mem/sizeclasstable.h b/src/mem/sizeclasstable.h index a69760463..432632f4b 100644 --- a/src/mem/sizeclasstable.h +++ b/src/mem/sizeclasstable.h @@ -39,7 +39,7 @@ namespace snmalloc // Large classes range from [MAX_SMALL_SIZECLASS_SIZE, ADDRESS_SPACE). static constexpr size_t NUM_LARGE_CLASSES = - Pal::address_bits - MAX_SMALL_SIZECLASS_BITS; + Pal::address_bits - MAX_SMALL_SIZECLASS_BITS; // How many bits are required to represent either a large or a small // sizeclass. diff --git a/src/mem/threadalloc.h b/src/mem/threadalloc.h index c7d23f1b0..19bf3b772 100644 --- a/src/mem/threadalloc.h +++ b/src/mem/threadalloc.h @@ -45,7 +45,7 @@ namespace snmalloc static void register_cleanup() {} public: - static SNMALLOC_FAST_PATH Alloc& get() + static SNMALLOC_FAST_PATH Alloc<>& get() { return ThreadAllocExternal::get(); } @@ -88,9 +88,10 @@ namespace snmalloc * It can be used during thread teardown, but its performance will be * less good. */ - static SNMALLOC_FAST_PATH Alloc& get() + template + static SNMALLOC_FAST_PATH Alloc<>& get() { - SNMALLOC_REQUIRE_CONSTINIT static thread_local Alloc alloc; + SNMALLOC_REQUIRE_CONSTINIT static thread_local Alloc<> alloc; return alloc; } }; diff --git a/src/override/malloc.cc b/src/override/malloc.cc index f40b2d89d..755261f24 100644 --- a/src/override/malloc.cc +++ b/src/override/malloc.cc @@ -31,6 +31,31 @@ extern "C" ThreadAlloc::get().dealloc(ptr); } + SNMALLOC_EXPORT void* SNMALLOC_NAME_MANGLE(malloc_conceal)(size_t size) + { + size_t sz = round_size(size); + return ThreadAlloc::get().alloc(sz); + } + + SNMALLOC_EXPORT void SNMALLOC_NAME_MANGLE(freezero)(void* p, size_t size) + { + if (SNMALLOC_UNLIKELY(p == nullptr)) + { + return; + } + + auto& a = ThreadAlloc::get(); + size_t sz = bits::min(size, a.alloc_size(p)); + + /* we are not trying to be fast here, but disallowing to potentially + * optimize away the memset call */ + + void* (*volatile memset_fn)(void*, int, size_t) = memset; + memset_fn(p, 0, sz); + + a.dealloc(p); + } + /** * Clang was helpfully inlining the constant return value, and * thus converting from a tail call to an ordinary call. @@ -54,6 +79,17 @@ extern "C" return ThreadAlloc::get().alloc(sz); } + SNMALLOC_EXPORT void* SNMALLOC_NAME_MANGLE(calloc_conceal)(size_t nmemb, size_t size) + { + bool overflow = false; + size_t sz = round_size(bits::umul(size, nmemb, overflow)); + if (SNMALLOC_UNLIKELY(overflow)) + { + return SNMALLOC_NAME_MANGLE(snmalloc_set_error)(); + } + return ThreadAlloc::get().alloc(sz); + } + SNMALLOC_EXPORT size_t SNMALLOC_NAME_MANGLE(malloc_usable_size)( MALLOC_USABLE_SIZE_QUALIFIER void* ptr) diff --git a/src/override/memcpy.cc b/src/override/memcpy.cc index 6c858f422..e14eaf0cb 100644 --- a/src/override/memcpy.cc +++ b/src/override/memcpy.cc @@ -118,7 +118,7 @@ namespace alloc.template external_pointer(p), alloc.template external_pointer(p), len); - Pal::error(buffer.data()); + Pal<>::error(buffer.data()); } /** diff --git a/src/override/override.h b/src/override/override.h index a9aedbe9d..fb1b64aca 100644 --- a/src/override/override.h +++ b/src/override/override.h @@ -8,7 +8,7 @@ // The default configuration for snmalloc is used if alternative not defined namespace snmalloc { - using Alloc = snmalloc::LocalAllocator; + template using Alloc = snmalloc::LocalAllocator; } // namespace snmalloc #endif diff --git a/src/pal/pal.h b/src/pal/pal.h index 096df25bf..f82424dd0 100644 --- a/src/pal/pal.h +++ b/src/pal/pal.h @@ -26,13 +26,14 @@ namespace snmalloc { #if !defined(OPEN_ENCLAVE) || defined(OPEN_ENCLAVE_SIMULATION) + template using DefaultPal = # if defined(_WIN32) PALWindows; # elif defined(__APPLE__) PALApple<>; # elif defined(__linux__) - PALLinux; + PALLinux; # elif defined(FreeBSD_KERNEL) PALFreeBSDKernel; # elif defined(__FreeBSD__) @@ -52,22 +53,23 @@ namespace snmalloc # endif #endif + template using Pal = #if defined(SNMALLOC_MEMORY_PROVIDER) PALPlainMixin; #elif defined(OPEN_ENCLAVE) PALOpenEnclave; #else - DefaultPal; + DefaultPal; #endif [[noreturn]] SNMALLOC_SLOW_PATH inline void error(const char* const str) { - Pal::error(str); + Pal::error(str); } // Used to keep Superslab metadata committed. - static constexpr size_t OS_PAGE_SIZE = Pal::page_size; + static constexpr size_t OS_PAGE_SIZE = Pal::page_size; /** * Perform platform-specific adjustment of return pointers. @@ -76,7 +78,7 @@ namespace snmalloc * disruption to PALs for platforms that do not support StrictProvenance AALs. */ template< - typename PAL = Pal, + typename PAL = Pal<>, typename AAL = Aal, typename T, SNMALLOC_CONCEPT(capptr::ConceptBound) B> @@ -89,7 +91,7 @@ namespace snmalloc } template< - typename PAL = Pal, + typename PAL = Pal<>, typename AAL = Aal, typename T, SNMALLOC_CONCEPT(capptr::ConceptBound) B> diff --git a/src/pal/pal_consts.h b/src/pal/pal_consts.h index 31df5470b..2fd289528 100644 --- a/src/pal/pal_consts.h +++ b/src/pal/pal_consts.h @@ -94,6 +94,18 @@ namespace snmalloc YesZero }; + enum CoreDump + { + /** + * Default mode, memory are being dumped into a core file + */ + DoDump, + /** + * Memory content not dumped into a core file + */ + DontDump, + }; + /** * Default Tag ID for the Apple class */ diff --git a/src/pal/pal_linux.h b/src/pal/pal_linux.h index 438a7469c..6f58c63a9 100644 --- a/src/pal/pal_linux.h +++ b/src/pal/pal_linux.h @@ -13,7 +13,8 @@ extern "C" int puts(const char* str); namespace snmalloc { - class PALLinux : public PALPOSIX + template + class PALLinux : public PALPOSIX> { public: /** @@ -22,10 +23,10 @@ namespace snmalloc * * We always make sure that linux has entropy support. */ - static constexpr uint64_t pal_features = PALPOSIX::pal_features | Entropy; + static constexpr uint64_t pal_features = PALPOSIX>::pal_features | Entropy; static constexpr size_t page_size = - Aal::aal_name == PowerPC ? 0x10000 : PALPOSIX::page_size; + Aal::aal_name == PowerPC ? 0x10000 : PALPOSIX>::page_size; /** * Linux requires an explicit no-reserve flag in `mmap` to guarantee lazy @@ -65,6 +66,21 @@ namespace snmalloc } } + static void* reserve(size_t size) noexcept + { + void* p = PALPOSIX>::reserve(size); + if (p) + { + if constexpr (CDM == DontDump) + { + SNMALLOC_ASSERT(is_aligned_block(p, size)); + madvise(p, size, MADV_DONTDUMP); + } + } + + return p; + } + static void notify_not_using(void* p, size_t size) noexcept { SNMALLOC_ASSERT(is_aligned_block(p, size)); diff --git a/src/snmalloc.h b/src/snmalloc.h index e1d90d402..65eb18fd6 100644 --- a/src/snmalloc.h +++ b/src/snmalloc.h @@ -14,7 +14,7 @@ // The default configuration for snmalloc namespace snmalloc { - using Alloc = snmalloc::LocalAllocator; + template using Alloc = snmalloc::LocalAllocator; } // User facing API surface, needs to know what `Alloc` is. diff --git a/src/test/func/domestication/domestication.cc b/src/test/func/domestication/domestication.cc index 7a5d2c077..26311a9ef 100644 --- a/src/test/func/domestication/domestication.cc +++ b/src/test/func/domestication/domestication.cc @@ -17,7 +17,7 @@ int main() # define SNMALLOC_PROVIDE_OWN_CONFIG namespace snmalloc { - class CustomGlobals : public BackendAllocator + class CustomGlobals : public BackendAllocator, false> { public: using GlobalPoolState = PoolState>; @@ -102,7 +102,7 @@ namespace snmalloc } }; - using Alloc = LocalAllocator; + template using Alloc = LocalAllocator; } # define SNMALLOC_NAME_MANGLE(a) test_##a @@ -114,10 +114,10 @@ int main() snmalloc::CustomGlobals::domesticate_count = 0; LocalEntropy entropy; - entropy.init(); + entropy.init>(); key_global = FreeListKey(entropy.get_free_list_key()); - auto alloc1 = new Alloc(); + auto alloc1 = new Alloc<>(); // Allocate from alloc1; the size doesn't matter a whole lot, it just needs to // be a small object and so definitely owned by this allocator rather. @@ -125,7 +125,7 @@ int main() std::cout << "Allocated p " << p << std::endl; // Put that free object on alloc1's remote queue - auto alloc2 = new Alloc(); + auto alloc2 = new Alloc<>(); alloc2->dealloc(p); alloc2->flush(); diff --git a/src/test/func/fixed_region/fixed_region.cc b/src/test/func/fixed_region/fixed_region.cc index 527377221..29bafd277 100644 --- a/src/test/func/fixed_region/fixed_region.cc +++ b/src/test/func/fixed_region/fixed_region.cc @@ -11,7 +11,7 @@ using namespace snmalloc; -using CustomGlobals = FixedGlobals>; +using CustomGlobals = FixedGlobals>>; using FixedAlloc = LocalAllocator; int main() @@ -23,8 +23,8 @@ int main() // It is also large enough for the example to run in. // For 1MiB superslabs, SUPERSLAB_BITS + 4 is not big enough for the example. auto size = bits::one_at_bit(28); - auto oe_base = Pal::reserve(size); - Pal::notify_using(oe_base, size); + auto oe_base = Pal<>::reserve(size); + Pal<>::notify_using(oe_base, size); auto oe_end = pointer_offset(oe_base, size); std::cout << "Allocated region " << oe_base << " - " << pointer_offset(oe_base, size) << std::endl; diff --git a/src/test/func/malloc/malloc.cc b/src/test/func/malloc/malloc.cc index a672a25a1..16bf27ab6 100644 --- a/src/test/func/malloc/malloc.cc +++ b/src/test/func/malloc/malloc.cc @@ -89,11 +89,20 @@ void check_result(size_t size, size_t align, void* p, int err, bool null) our_free(p); } -void test_calloc(size_t nmemb, size_t size, int err, bool null) +void test_calloc( + void* (*calloc_fn)(size_t, size_t), + size_t nmemb, + size_t size, + int err, + bool null) { - printf("calloc(%zu, %zu) combined size %zu\n", nmemb, size, nmemb * size); + printf("calloc"); + if (calloc_fn == our_calloc_conceal) + printf("_conceal"); + + printf("(%zu, %zu) combined size %zu\n", nmemb, size, nmemb * size); errno = SUCCESS; - void* p = our_calloc(nmemb, size); + void* p = calloc_fn(nmemb, size); if (p != nullptr) { @@ -213,7 +222,7 @@ int main(int argc, char** argv) check_result(size + 1, 1, our_malloc(size + 1), SUCCESS, false); } - test_calloc(0, 0, SUCCESS, false); + test_calloc(our_calloc, 0, 0, SUCCESS, false); our_free(nullptr); @@ -229,10 +238,10 @@ int main(int argc, char** argv) if (overflow) break; - test_calloc(n, size, SUCCESS, false); - test_calloc(n, 0, SUCCESS, false); + test_calloc(our_calloc, n, size, SUCCESS, false); + test_calloc(our_calloc, n, 0, SUCCESS, false); } - test_calloc(0, size, SUCCESS, false); + test_calloc(our_calloc, 0, size, SUCCESS, false); } for (smallsizeclass_t sc = 0; sc < NUM_SMALL_SIZECLASSES; sc++) @@ -265,6 +274,44 @@ int main(int argc, char** argv) } test_realloc(our_malloc(64), 4194304, SUCCESS, false); +for (smallsizeclass_t sc = 0; sc < (MAX_SMALL_SIZECLASS_BITS + 4); sc++) + { + const size_t size = bits::one_at_bit(sc); + printf("malloc_conceal: %zu\n", size); + errno = SUCCESS; + check_result(size, 1, our_malloc_conceal(size), SUCCESS, false); + errno = SUCCESS; + check_result(size + 1, 1, our_malloc_conceal(size + 1), SUCCESS, false); + } + + our_freezero(nullptr, 1024); + void* p = our_malloc_conceal(64); + our_freezero(p, 128); + if (((uint8_t*)p)[63] != 0) + { + abort(); + } + + p = our_malloc_conceal(16); + our_freezero(p, 0); + + for (smallsizeclass_t sc = 0; sc < NUM_SMALL_SIZECLASSES; sc++) + { + const size_t size = sizeclass_to_size(sc); + + bool overflow = false; + for (size_t n = 1; + bits::umul(size, n, overflow) <= MAX_SMALL_SIZECLASS_SIZE; + n *= 5) + { + if (overflow) + break; + + test_calloc(our_calloc_conceal, n, size, SUCCESS, false); + test_calloc(our_calloc_conceal, n, 0, SUCCESS, false); + } + test_calloc(our_calloc_conceal, 0, size, SUCCESS, false); + } test_posix_memalign(0, 0, EINVAL, true); test_posix_memalign(((size_t)-1) / 2, 0, EINVAL, true); diff --git a/src/test/func/memory/memory.cc b/src/test/func/memory/memory.cc index a650a7c8d..f9f8e5356 100644 --- a/src/test/func/memory/memory.cc +++ b/src/test/func/memory/memory.cc @@ -304,7 +304,7 @@ void test_external_pointer_large() auto& alloc = ThreadAlloc::get(); - constexpr size_t count_log = Pal::address_bits > 32 ? 5 : 3; + constexpr size_t count_log = Pal<>::address_bits > 32 ? 5 : 3; constexpr size_t count = 1 << count_log; // Pre allocate all the objects size_t* objects[count]; diff --git a/src/test/func/pagemap/pagemap.cc b/src/test/func/pagemap/pagemap.cc index 410ba8cd2..d30732604 100644 --- a/src/test/func/pagemap/pagemap.cc +++ b/src/test/func/pagemap/pagemap.cc @@ -21,11 +21,11 @@ struct T T() {} }; -AddressSpaceManager address_space; +AddressSpaceManager> address_space; -FlatPagemap pagemap_test_unbound; +FlatPagemap, false> pagemap_test_unbound; -FlatPagemap pagemap_test_bound; +FlatPagemap, true> pagemap_test_bound; size_t failure_count = 0; @@ -69,8 +69,8 @@ void test_pagemap(bool bounded) if (bounded) { auto size = bits::one_at_bit(30); - auto base = Pal::reserve(size); - Pal::notify_using(base, size); + auto base = Pal<>::reserve(size); + Pal<>::notify_using(base, size); std::cout << "Fixed base: " << base << " (" << size << ") " << " end: " << pointer_offset(base, size) << std::endl; auto [heap_base, heap_size] = pagemap_test_bound.init(base, size); diff --git a/src/test/func/pool/pool.cc b/src/test/func/pool/pool.cc index 7d63e9e2a..a7e92627e 100644 --- a/src/test/func/pool/pool.cc +++ b/src/test/func/pool/pool.cc @@ -12,7 +12,7 @@ struct PoolAEntry : Pooled PoolAEntry() : field(1){}; }; -using PoolA = Pool; +using PoolA = Pool::StateHandle>; struct PoolBEntry : Pooled { @@ -22,14 +22,14 @@ struct PoolBEntry : Pooled PoolBEntry(int f) : field(f){}; }; -using PoolB = Pool; +using PoolB = Pool::StateHandle>; void test_alloc() { auto ptr = PoolA::acquire(); SNMALLOC_CHECK(ptr != nullptr); // Pool allocations should not be visible to debug_check_empty. - snmalloc::debug_check_empty(); + snmalloc::debug_check_empty::StateHandle>(); PoolA::release(ptr); } diff --git a/src/test/func/sandbox/sandbox.cc b/src/test/func/sandbox/sandbox.cc index 519488070..2bfc3b5c4 100644 --- a/src/test/func/sandbox/sandbox.cc +++ b/src/test/func/sandbox/sandbox.cc @@ -31,7 +31,7 @@ namespace */ struct Sandbox { - using NoOpPal = PALNoAlloc; + using NoOpPal = PALNoAlloc>; struct ArenaMap { @@ -237,7 +237,7 @@ namespace } private: - template + template> void* alloc_sandbox_heap(size_t sb_size) { // Use the outside-sandbox snmalloc to allocate memory, rather than using diff --git a/src/test/func/statistics/stats.cc b/src/test/func/statistics/stats.cc index 156612c27..af006b692 100644 --- a/src/test/func/statistics/stats.cc +++ b/src/test/func/statistics/stats.cc @@ -3,7 +3,7 @@ int main() { #ifndef SNMALLOC_PASS_THROUGH // This test depends on snmalloc internals - snmalloc::Alloc& a = snmalloc::ThreadAlloc::get(); + snmalloc::Alloc<>& a = snmalloc::ThreadAlloc::get(); bool result; auto r = a.alloc(16); diff --git a/src/test/func/thread_alloc_external/thread_alloc_external.cc b/src/test/func/thread_alloc_external/thread_alloc_external.cc index bc0952e2e..d592b4ea2 100644 --- a/src/test/func/thread_alloc_external/thread_alloc_external.cc +++ b/src/test/func/thread_alloc_external/thread_alloc_external.cc @@ -12,7 +12,7 @@ namespace snmalloc { - using Alloc = snmalloc::LocalAllocator; + template using Alloc = snmalloc::LocalAllocator; } using namespace snmalloc; @@ -20,13 +20,13 @@ using namespace snmalloc; class ThreadAllocExternal { public: - static Alloc*& get_inner() + static Alloc<>*& get_inner() { - static thread_local Alloc* alloc; + static thread_local Alloc<>* alloc; return alloc; } - static Alloc& get() + static Alloc<>& get() { return *get_inner(); } @@ -41,10 +41,10 @@ void allocator_thread_init(void) // Create bootstrap allocator auto a = snmalloc::ScopedAllocator(); // Create storage for the thread-local allocator - aptr = a->alloc(sizeof(snmalloc::Alloc)); + aptr = a->alloc(sizeof(snmalloc::Alloc<>)); } // Initialize the thread-local allocator - ThreadAllocExternal::get_inner() = new (aptr) snmalloc::Alloc(); + ThreadAllocExternal::get_inner() = new (aptr) snmalloc::Alloc<>(); ThreadAllocExternal::get().init(); } diff --git a/src/test/func/two_alloc_types/alloc1.cc b/src/test/func/two_alloc_types/alloc1.cc index 8a21c8004..0c829b84a 100644 --- a/src/test/func/two_alloc_types/alloc1.cc +++ b/src/test/func/two_alloc_types/alloc1.cc @@ -10,8 +10,8 @@ #define SNMALLOC_PROVIDE_OWN_CONFIG namespace snmalloc { - using CustomGlobals = FixedGlobals>; - using Alloc = LocalAllocator; + using CustomGlobals = FixedGlobals>>; + template using Alloc = LocalAllocator; } #define SNMALLOC_NAME_MANGLE(a) enclave_##a diff --git a/src/test/perf/external_pointer/externalpointer.cc b/src/test/perf/external_pointer/externalpointer.cc index e2fdb06be..6b8d3d484 100644 --- a/src/test/perf/external_pointer/externalpointer.cc +++ b/src/test/perf/external_pointer/externalpointer.cc @@ -13,13 +13,13 @@ namespace test // Pre allocate all the objects size_t* objects[count]; - NOINLINE void setup(xoroshiro::p128r64& r, Alloc& alloc) + NOINLINE void setup(xoroshiro::p128r64& r, Alloc<>& alloc) { for (size_t i = 0; i < count; i++) { size_t rand = (size_t)r.next(); size_t offset = bits::clz(rand); - if constexpr (Pal::address_bits > 32) + if constexpr (Pal<>::address_bits > 32) { if (offset > 30) offset = 30; @@ -39,7 +39,7 @@ namespace test } } - NOINLINE void teardown(Alloc& alloc) + NOINLINE void teardown(Alloc<>& alloc) { // Deallocate everything for (size_t i = 0; i < count; i++)