diff --git a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp --- a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp @@ -14,6 +14,7 @@ #include "combined.h" #include "mem_map.h" +#include #include #include #include @@ -69,6 +70,8 @@ } } +static size_t NumAllocatorInstances = 0; + template struct TestAllocator : scudo::Allocator { TestAllocator() { this->initThreadMaybe(); @@ -78,13 +81,11 @@ } ~TestAllocator() { this->unmapTestOnly(); } - void *operator new(size_t size) { - void *p = nullptr; - EXPECT_EQ(0, posix_memalign(&p, alignof(TestAllocator), size)); - return p; + void *operator new(size_t size); + void operator delete(void *ptr) { + ASSERT_EQ(NumAllocatorInstances, 1u); + NumAllocatorInstances--; } - - void operator delete(void *ptr) { free(ptr); } }; template struct ScudoCombinedTest : public Test { @@ -111,11 +112,25 @@ #define SCUDO_TYPED_TEST_ALL_TYPES(FIXTURE, NAME) \ SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, AndroidSvelteConfig) \ SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, FuchsiaConfig) +constexpr size_t kMaxSize = + std::max({sizeof(TestAllocator), + sizeof(TestAllocator)}); +constexpr size_t kMaxAlign = + std::max({alignof(TestAllocator), + alignof(TestAllocator)}); #else #define SCUDO_TYPED_TEST_ALL_TYPES(FIXTURE, NAME) \ SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, AndroidSvelteConfig) \ SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, DefaultConfig) \ SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, AndroidConfig) +constexpr size_t kMaxSize = + std::max({sizeof(TestAllocator), + sizeof(TestAllocator), + sizeof(TestAllocator)}); +constexpr size_t kMaxAlign = + std::max({alignof(TestAllocator), + alignof(TestAllocator), + alignof(TestAllocator)}); #endif #define SCUDO_TYPED_TEST_TYPE(FIXTURE, NAME, TYPE) \ @@ -130,6 +145,20 @@ SCUDO_TYPED_TEST_ALL_TYPES(FIXTURE, NAME) \ template void FIXTURE##NAME::Run() +// The allocator is over 4MB large. Rather than creating an instance of this on +// the heap, keep it in a global storage to reduce fragmentation from having to +// mmap this at the start of every test. +alignas(kMaxAlign) static uint8_t AllocatorStorage[kMaxSize]; + +template +void *TestAllocator::operator new(size_t size) { + assert(size <= sizeof(AllocatorStorage) && + "Allocation size doesn't fit in the allocator storage"); + assert(NumAllocatorInstances == 0 && "Allocator storage already in use"); + NumAllocatorInstances++; + return AllocatorStorage; +} + SCUDO_TYPED_TEST(ScudoCombinedTest, IsOwned) { auto *Allocator = this->Allocator.get(); static scudo::u8 StaticBuffer[scudo::Chunk::getHeaderSize() + 1];