From 7fc975aa26f2e0ce6c80629209115ea58b245da5 Mon Sep 17 00:00:00 2001 From: Fabio D'Urso Date: Wed, 19 Jun 2024 09:37:23 +0200 Subject: Reland "[scudo] Apply filling when realloc shrinks and re-grows a block in-place" (#95838) Reland of #93212, which had been reverted in commit bddd8eae17df6511aee789744ccdc158de817081. --- compiler-rt/lib/scudo/standalone/combined.h | 13 ++++++++++++ .../lib/scudo/standalone/tests/combined_test.cpp | 23 +++++++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h index f9ed365..fcf6565 100644 --- a/compiler-rt/lib/scudo/standalone/combined.h +++ b/compiler-rt/lib/scudo/standalone/combined.h @@ -549,6 +549,19 @@ public: // header to reflect the size change. if (reinterpret_cast(OldTaggedPtr) + NewSize <= BlockEnd) { if (NewSize > OldSize || (OldSize - NewSize) < getPageSizeCached()) { + // If we have reduced the size, set the extra bytes to the fill value + // so that we are ready to grow it again in the future. + if (NewSize < OldSize) { + const FillContentsMode FillContents = + TSDRegistry.getDisableMemInit() ? NoFill + : Options.getFillContentsMode(); + if (FillContents != NoFill) { + memset(reinterpret_cast(OldTaggedPtr) + NewSize, + FillContents == ZeroFill ? 0 : PatternFillByte, + OldSize - NewSize); + } + } + Header.SizeOrUnusedBytes = (ClassId ? NewSize : BlockEnd - diff --git a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp index 1a36155..16b19e8 100644 --- a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp @@ -447,19 +447,32 @@ SCUDO_TYPED_TEST(ScudoCombinedDeathTest, ReallocateSame) { // returns the same chunk. This requires that all the sizes we iterate on use // the same block size, but that should be the case for MaxSize - 64 with our // default class size maps. - constexpr scudo::uptr ReallocSize = + constexpr scudo::uptr InitialSize = TypeParam::Primary::SizeClassMap::MaxSize - 64; - void *P = Allocator->allocate(ReallocSize, Origin); const char Marker = 'A'; - memset(P, Marker, ReallocSize); + Allocator->setFillContents(scudo::PatternOrZeroFill); + + void *P = Allocator->allocate(InitialSize, Origin); + scudo::uptr CurrentSize = InitialSize; for (scudo::sptr Delta = -32; Delta < 32; Delta += 8) { + memset(P, Marker, CurrentSize); const scudo::uptr NewSize = - static_cast(static_cast(ReallocSize) + Delta); + static_cast(static_cast(InitialSize) + Delta); void *NewP = Allocator->reallocate(P, NewSize); EXPECT_EQ(NewP, P); - for (scudo::uptr I = 0; I < ReallocSize - 32; I++) + + // Verify that existing contents have been preserved. + for (scudo::uptr I = 0; I < scudo::Min(CurrentSize, NewSize); I++) EXPECT_EQ((reinterpret_cast(NewP))[I], Marker); + + // Verify that new bytes are set according to FillContentsMode. + for (scudo::uptr I = CurrentSize; I < NewSize; I++) { + unsigned char V = (reinterpret_cast(NewP))[I]; + EXPECT_TRUE(V == scudo::PatternFillByte || V == 0); + } + checkMemoryTaggingMaybe(Allocator, NewP, NewSize, 0); + CurrentSize = NewSize; } Allocator->deallocate(P, Origin); } -- cgit v1.1