Index: compiler-rt/trunk/lib/scudo/standalone/bytemap.h =================================================================== --- compiler-rt/trunk/lib/scudo/standalone/bytemap.h +++ compiler-rt/trunk/lib/scudo/standalone/bytemap.h @@ -22,6 +22,8 @@ } void init() { initLinkerInitialized(); } + void unmapTestOnly() { unmap(reinterpret_cast(Map), Size); } + void set(uptr Index, u8 Value) { DCHECK_LT(Index, Size); DCHECK_EQ(0U, Map[Index]); @@ -57,6 +59,12 @@ memset(Level1Map, 0, sizeof(atomic_uptr) * Level1Size); } + void unmapTestOnly() { + reset(); + unmap(reinterpret_cast(Level1Map), + sizeof(atomic_uptr) * Level1Size); + } + uptr size() const { return Level1Size * Level2Size; } void set(uptr Index, u8 Value) { Index: compiler-rt/trunk/lib/scudo/standalone/primary32.h =================================================================== --- compiler-rt/trunk/lib/scudo/standalone/primary32.h +++ compiler-rt/trunk/lib/scudo/standalone/primary32.h @@ -83,6 +83,17 @@ initLinkerInitialized(ReleaseToOsInterval); } + void unmapTestOnly() { + while (NumberOfStashedRegions > 0) + unmap(reinterpret_cast(RegionsStash[--NumberOfStashedRegions]), + RegionSize); + // TODO(kostyak): unmap the TransferBatch regions as well. + for (uptr I = 0; I < NumRegions; I++) + if (PossibleRegions[I]) + unmap(reinterpret_cast(I * RegionSize), RegionSize); + PossibleRegions.unmapTestOnly(); + } + TransferBatch *popBatch(CacheT *C, uptr ClassId) { DCHECK_LT(ClassId, NumClasses); SizeClassInfo *Sci = getSizeClassInfo(ClassId); Index: compiler-rt/trunk/lib/scudo/standalone/primary64.h =================================================================== --- compiler-rt/trunk/lib/scudo/standalone/primary64.h +++ compiler-rt/trunk/lib/scudo/standalone/primary64.h @@ -91,6 +91,12 @@ initLinkerInitialized(ReleaseToOsInterval); } + void unmapTestOnly() { + unmap(reinterpret_cast(PrimaryBase), PrimarySize, UNMAP_ALL, &Data); + unmap(reinterpret_cast(RegionInfoArray), + sizeof(RegionInfo) * NumClasses); + } + TransferBatch *popBatch(CacheT *C, uptr ClassId) { DCHECK_LT(ClassId, NumClasses); RegionInfo *Region = getRegionInfo(ClassId); Index: compiler-rt/trunk/lib/scudo/standalone/tests/bytemap_test.cc =================================================================== --- compiler-rt/trunk/lib/scudo/standalone/tests/bytemap_test.cc +++ compiler-rt/trunk/lib/scudo/standalone/tests/bytemap_test.cc @@ -28,13 +28,14 @@ const scudo::uptr Size = 1U << 10; scudo::FlatByteMap Map; testMap(Map, Size); + Map.unmapTestOnly(); } TEST(ScudoByteMapTest, TwoLevelByteMap) { const scudo::uptr Size1 = 1U << 6, Size2 = 1U << 12; scudo::TwoLevelByteMap Map; testMap(Map, Size1 * Size2); - Map.reset(); + Map.unmapTestOnly(); } using TestByteMap = scudo::TwoLevelByteMap<1U << 12, 1U << 13>; @@ -69,5 +70,5 @@ } for (scudo::uptr I = 0; I < NumberOfThreads; I++) pthread_join(T[I], 0); - Map.reset(); + Map.unmapTestOnly(); } Index: compiler-rt/trunk/lib/scudo/standalone/tests/primary_test.cc =================================================================== --- compiler-rt/trunk/lib/scudo/standalone/tests/primary_test.cc +++ compiler-rt/trunk/lib/scudo/standalone/tests/primary_test.cc @@ -22,7 +22,11 @@ template static void testPrimary() { const scudo::uptr NumberOfAllocations = 32U; - std::unique_ptr Allocator(new Primary); + auto Deleter = [](Primary *P) { + P->unmapTestOnly(); + delete P; + }; + std::unique_ptr Allocator(new Primary, Deleter); Allocator->init(/*ReleaseToOsInterval=*/-1); typename Primary::CacheT Cache; Cache.init(nullptr, Allocator.get()); @@ -84,10 +88,15 @@ Allocator.releaseToOS(); Allocator.printStats(); EXPECT_EQ(AllocationFailed, true); + Allocator.unmapTestOnly(); } template static void testIteratePrimary() { - std::unique_ptr Allocator(new Primary); + auto Deleter = [](Primary *P) { + P->unmapTestOnly(); + delete P; + }; + std::unique_ptr Allocator(new Primary, Deleter); Allocator->init(/*ReleaseToOsInterval=*/-1); typename Primary::CacheT Cache; Cache.init(nullptr, Allocator.get()); @@ -125,10 +134,6 @@ testIteratePrimary>(); } -// TODO(kostyak): reenable on 32-bit after implementing unmapTestOnly for the -// primary: we are running out of addressable space without. -#if SCUDO_WORDSIZE == 64U - static std::mutex Mutex; static std::condition_variable Cv; static bool Ready = false; @@ -143,7 +148,7 @@ Cv.wait(Lock); } for (scudo::uptr I = 0; I < 256U; I++) { - const scudo::uptr Size = std::rand() % Primary::SizeClassMap::MaxSize; + const scudo::uptr Size = std::rand() % Primary::SizeClassMap::MaxSize / 4; const scudo::uptr ClassId = Primary::SizeClassMap::getClassIdBySize(Size); void *P = Cache.allocate(ClassId); if (P) @@ -158,7 +163,11 @@ } template static void testPrimaryThreaded() { - std::unique_ptr Allocator(new Primary); + auto Deleter = [](Primary *P) { + P->unmapTestOnly(); + delete P; + }; + std::unique_ptr Allocator(new Primary, Deleter); Allocator->init(/*ReleaseToOsInterval=*/-1); std::thread Threads[32]; for (scudo::uptr I = 0; I < ARRAY_SIZE(Threads); I++) @@ -177,7 +186,5 @@ TEST(ScudoPrimaryTest, PrimaryThreaded) { using SizeClassMap = scudo::SvelteSizeClassMap; testPrimaryThreaded>(); - testPrimaryThreaded>(); + testPrimaryThreaded>(); } - -#endif // SCUDO_WORDSIZE == 64U Index: compiler-rt/trunk/lib/scudo/standalone/tests/tsd_test.cc =================================================================== --- compiler-rt/trunk/lib/scudo/standalone/tests/tsd_test.cc +++ compiler-rt/trunk/lib/scudo/standalone/tests/tsd_test.cc @@ -32,6 +32,7 @@ } void reset() { memset(this, 0, sizeof(*this)); } + void unmapTestOnly() { TSDRegistry.unmapTestOnly(); } void initCache(CacheT *Cache) { memset(Cache, 0, sizeof(*Cache)); } void commitBack(scudo::TSD *TSD) {} TSDRegistryT *getTSDRegistry() { return &TSDRegistry; } @@ -60,7 +61,12 @@ TEST(ScudoTSDTest, TSDRegistryInit) { using AllocatorT = MockAllocator; - std::unique_ptr Allocator(new AllocatorT); + auto Deleter = [](AllocatorT *A) { + A->unmapTestOnly(); + delete A; + }; + std::unique_ptr Allocator(new AllocatorT, + Deleter); Allocator->reset(); EXPECT_FALSE(Allocator->isInitialized()); @@ -70,7 +76,12 @@ } template static void testRegistry() { - std::unique_ptr Allocator(new AllocatorT); + auto Deleter = [](AllocatorT *A) { + A->unmapTestOnly(); + delete A; + }; + std::unique_ptr Allocator(new AllocatorT, + Deleter); Allocator->reset(); EXPECT_FALSE(Allocator->isInitialized()); @@ -131,7 +142,12 @@ } template static void testRegistryThreaded() { - std::unique_ptr Allocator(new AllocatorT); + auto Deleter = [](AllocatorT *A) { + A->unmapTestOnly(); + delete A; + }; + std::unique_ptr Allocator(new AllocatorT, + Deleter); Allocator->reset(); std::thread Threads[32]; for (scudo::uptr I = 0; I < ARRAY_SIZE(Threads); I++) Index: compiler-rt/trunk/lib/scudo/standalone/tsd_exclusive.h =================================================================== --- compiler-rt/trunk/lib/scudo/standalone/tsd_exclusive.h +++ compiler-rt/trunk/lib/scudo/standalone/tsd_exclusive.h @@ -37,6 +37,10 @@ initLinkerInitialized(Instance); } + void unmapTestOnly() { + unmap(reinterpret_cast(FallbackTSD), sizeof(TSD)); + } + ALWAYS_INLINE void initThreadMaybe(Allocator *Instance, bool MinimalInit) { if (LIKELY(State != ThreadState::NotInitialized)) return; Index: compiler-rt/trunk/lib/scudo/standalone/tsd_shared.h =================================================================== --- compiler-rt/trunk/lib/scudo/standalone/tsd_shared.h +++ compiler-rt/trunk/lib/scudo/standalone/tsd_shared.h @@ -47,6 +47,11 @@ initLinkerInitialized(Instance); } + void unmapTestOnly() { + unmap(reinterpret_cast(TSDs), + sizeof(TSD) * NumberOfTSDs); + } + ALWAYS_INLINE void initThreadMaybe(Allocator *Instance, UNUSED bool MinimalInit) { if (LIKELY(getCurrentTSD()))