diff --git a/compiler-rt/lib/scudo/standalone/primary32.h b/compiler-rt/lib/scudo/standalone/primary32.h index 7f608aeac2962..6e791a127df66 100644 --- a/compiler-rt/lib/scudo/standalone/primary32.h +++ b/compiler-rt/lib/scudo/standalone/primary32.h @@ -725,6 +725,9 @@ template class SizeClassAllocator32 { Context.markFreeBlocks(BG.Batches, DecompactPtr, Base); } + if (!Context.hasBlockMarked()) + return 0; + auto SkipRegion = [this, First, ClassId](uptr RegionIndex) { return (PossibleRegions[First + RegionIndex] - 1U) != ClassId; }; diff --git a/compiler-rt/lib/scudo/standalone/primary64.h b/compiler-rt/lib/scudo/standalone/primary64.h index 182c22752e9ae..a3684c9d45864 100644 --- a/compiler-rt/lib/scudo/standalone/primary64.h +++ b/compiler-rt/lib/scudo/standalone/primary64.h @@ -728,6 +728,9 @@ template class SizeClassAllocator64 { Context.markFreeBlocks(BG.Batches, DecompactPtr, Region->RegionBeg); } + if (!Context.hasBlockMarked()) + return 0; + auto SkipRegion = [](UNUSED uptr RegionIndex) { return false; }; releaseFreeMemoryToOS(Context, Recorder, SkipRegion); diff --git a/compiler-rt/lib/scudo/standalone/release.h b/compiler-rt/lib/scudo/standalone/release.h index 12cc8d2c7173b..ef5f23208dff4 100644 --- a/compiler-rt/lib/scudo/standalone/release.h +++ b/compiler-rt/lib/scudo/standalone/release.h @@ -258,7 +258,16 @@ struct PageReleaseContext { PageSizeLog = getLog2(PageSize); RoundedRegionSize = PagesCount << PageSizeLog; RoundedSize = NumberOfRegions * RoundedRegionSize; + } + + // PageMap is lazily allocated when markFreeBlocks() is invoked. + bool hasBlockMarked() const { + return PageMap.isAllocated(); + } + void ensurePageMapAllocated() { + if (PageMap.isAllocated()) + return; PageMap.reset(NumberOfRegions, PagesCount, FullPagesBlockCountMax); DCHECK(PageMap.isAllocated()); } @@ -266,6 +275,8 @@ struct PageReleaseContext { template void markFreeBlocks(const IntrusiveList &FreeList, DecompactPtrT DecompactPtr, uptr Base) { + ensurePageMapAllocated(); + // Iterate over free chunks and count how many free chunks affect each // allocated page. if (BlockSize <= PageSize && PageSize % BlockSize == 0) { diff --git a/compiler-rt/lib/scudo/standalone/tests/release_test.cpp b/compiler-rt/lib/scudo/standalone/tests/release_test.cpp index 0c3c043d1e087..8625e7fb4b767 100644 --- a/compiler-rt/lib/scudo/standalone/tests/release_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/release_test.cpp @@ -199,7 +199,9 @@ template void testReleaseFreeMemoryToOS() { scudo::PageReleaseContext Context(BlockSize, /*RegionSize=*/MaxBlocks * BlockSize, /*NumberOfRegions=*/1U); + ASSERT_FALSE(Context.hasBlockMarked()); Context.markFreeBlocks(FreeList, DecompactPtr, Recorder.getBase()); + ASSERT_TRUE(Context.hasBlockMarked()); releaseFreeMemoryToOS(Context, Recorder, SkipRegion); scudo::RegionPageMap &PageMap = Context.PageMap;