[compiler-rt] 45b7d44 - [scudo] Zero- and pattern-initialization of memory.
Evgenii Stepanov via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 30 15:01:09 PDT 2020
Author: Evgenii Stepanov
Date: 2020-04-30T15:00:55-07:00
New Revision: 45b7d44ecb01780e26dc8d3c30bc34e32c08dd70
URL: https://github.com/llvm/llvm-project/commit/45b7d44ecb01780e26dc8d3c30bc34e32c08dd70
DIFF: https://github.com/llvm/llvm-project/commit/45b7d44ecb01780e26dc8d3c30bc34e32c08dd70.diff
LOG: [scudo] Zero- and pattern-initialization of memory.
Summary:
Implement pattern initialization of memory (excluding the secondary
allocator because it already has predictable memory contents).
Expose both zero and pattern initialization through the C API.
Reviewers: pcc, cryptoad
Subscribers: #sanitizers, llvm-commits
Tags: #sanitizers
Differential Revision: https://reviews.llvm.org/D79133
Added:
Modified:
compiler-rt/lib/scudo/standalone/combined.h
compiler-rt/lib/scudo/standalone/common.h
compiler-rt/lib/scudo/standalone/flags.inc
compiler-rt/lib/scudo/standalone/secondary.h
compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
compiler-rt/lib/scudo/standalone/wrappers_c.inc
Removed:
################################################################################
diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h
index 66638e7dd5db..112aefdc3930 100644
--- a/compiler-rt/lib/scudo/standalone/combined.h
+++ b/compiler-rt/lib/scudo/standalone/combined.h
@@ -147,7 +147,10 @@ class Allocator {
// Store some flags locally.
Options.MayReturnNull = getFlags()->may_return_null;
- Options.ZeroContents = getFlags()->zero_contents;
+ Options.FillContents =
+ getFlags()->zero_contents
+ ? ZeroFill
+ : (getFlags()->pattern_fill_contents ? PatternOrZeroFill : NoFill);
Options.DeallocTypeMismatch = getFlags()->dealloc_type_mismatch;
Options.DeleteSizeMismatch = getFlags()->delete_size_mismatch;
Options.TrackAllocationStacks = false;
@@ -256,7 +259,8 @@ class Allocator {
}
#endif // GWP_ASAN_HOOKS
- ZeroContents |= static_cast<bool>(Options.ZeroContents);
+ FillContentsMode FillContents =
+ ZeroContents ? ZeroFill : Options.FillContents;
if (UNLIKELY(Alignment > MaxAlignment)) {
if (Options.MayReturnNull)
@@ -309,7 +313,7 @@ class Allocator {
}
if (UNLIKELY(ClassId == 0))
Block = Secondary.allocate(NeededSize, Alignment, &SecondaryBlockEnd,
- ZeroContents);
+ FillContents);
if (UNLIKELY(!Block)) {
if (Options.MayReturnNull)
@@ -391,10 +395,11 @@ class Allocator {
TaggedPtr = prepareTaggedChunk(Ptr, Size, BlockEnd);
}
storeAllocationStackMaybe(Ptr);
- } else if (UNLIKELY(ZeroContents)) {
+ } else if (UNLIKELY(FillContents != NoFill)) {
// This condition is not necessarily unlikely, but since memset is
// costly, we might as well mark it as such.
- memset(Block, 0, PrimaryT::getSizeByClassId(ClassId));
+ memset(Block, FillContents == ZeroFill ? 0 : PatternFillByte,
+ PrimaryT::getSizeByClassId(ClassId));
}
}
@@ -725,6 +730,11 @@ class Allocator {
Options.TrackAllocationStacks = Track;
}
+ void setFillContents(FillContentsMode FillContents) {
+ initThreadMaybe();
+ Options.FillContents = FillContents;
+ }
+
const char *getStackDepotAddress() const {
return reinterpret_cast<const char *>(&Depot);
}
@@ -899,7 +909,7 @@ class Allocator {
struct {
u8 MayReturnNull : 1; // may_return_null
- u8 ZeroContents : 1; // zero_contents
+ FillContentsMode FillContents : 2; // zero_contents, pattern_fill_contents
u8 DeallocTypeMismatch : 1; // dealloc_type_mismatch
u8 DeleteSizeMismatch : 1; // delete_size_mismatch
u8 TrackAllocationStacks : 1;
diff --git a/compiler-rt/lib/scudo/standalone/common.h b/compiler-rt/lib/scudo/standalone/common.h
index 350d8d9fcd91..9037f92b4976 100644
--- a/compiler-rt/lib/scudo/standalone/common.h
+++ b/compiler-rt/lib/scudo/standalone/common.h
@@ -182,6 +182,15 @@ struct BlockInfo {
uptr RegionEnd;
};
+constexpr unsigned char PatternFillByte = 0xAB;
+
+enum FillContentsMode {
+ NoFill = 0,
+ ZeroFill = 1,
+ PatternOrZeroFill = 2 // Pattern fill unless the memory is known to be
+ // zero-initialized already.
+};
+
} // namespace scudo
#endif // SCUDO_COMMON_H_
diff --git a/compiler-rt/lib/scudo/standalone/flags.inc b/compiler-rt/lib/scudo/standalone/flags.inc
index 342af1c79ad6..b5cab4734166 100644
--- a/compiler-rt/lib/scudo/standalone/flags.inc
+++ b/compiler-rt/lib/scudo/standalone/flags.inc
@@ -34,6 +34,9 @@ SCUDO_FLAG(bool, delete_size_mismatch, true,
SCUDO_FLAG(bool, zero_contents, false, "Zero chunk contents on allocation.")
+SCUDO_FLAG(bool, pattern_fill_contents, false,
+ "Pattern fill chunk contents on allocation.")
+
SCUDO_FLAG(int, rss_limit_mb, -1,
"Enforce an upper limit (in megabytes) to the process RSS. The "
"allocator will terminate or return NULL when allocations are "
diff --git a/compiler-rt/lib/scudo/standalone/secondary.h b/compiler-rt/lib/scudo/standalone/secondary.h
index 9d5f130f2d45..84eaa5091b43 100644
--- a/compiler-rt/lib/scudo/standalone/secondary.h
+++ b/compiler-rt/lib/scudo/standalone/secondary.h
@@ -236,7 +236,7 @@ template <class CacheT> class MapAllocator {
}
void *allocate(uptr Size, uptr AlignmentHint = 0, uptr *BlockEnd = nullptr,
- bool ZeroContents = false);
+ FillContentsMode FillContents = NoFill);
void deallocate(void *Ptr);
@@ -299,7 +299,8 @@ template <class CacheT> class MapAllocator {
// (pending rounding and headers).
template <class CacheT>
void *MapAllocator<CacheT>::allocate(uptr Size, uptr AlignmentHint,
- uptr *BlockEnd, bool ZeroContents) {
+ uptr *BlockEnd,
+ FillContentsMode FillContents) {
DCHECK_GE(Size, AlignmentHint);
const uptr PageSize = getPageSizeCached();
const uptr RoundedSize =
@@ -312,8 +313,9 @@ void *MapAllocator<CacheT>::allocate(uptr Size, uptr AlignmentHint,
*BlockEnd = H->BlockEnd;
void *Ptr = reinterpret_cast<void *>(reinterpret_cast<uptr>(H) +
LargeBlock::getHeaderSize());
- if (ZeroContents)
- memset(Ptr, 0, H->BlockEnd - reinterpret_cast<uptr>(Ptr));
+ if (FillContents)
+ memset(Ptr, FillContents == ZeroFill ? 0 : PatternFillByte,
+ H->BlockEnd - reinterpret_cast<uptr>(Ptr));
const uptr BlockSize = H->BlockEnd - reinterpret_cast<uptr>(H);
{
ScopedLock L(Mutex);
diff --git a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
index a6f29a2610ed..b9e1be1f32e8 100644
--- a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
@@ -115,7 +115,44 @@ template <class Config> static void testAllocator() {
void *P = Allocator->allocate(Size, Origin, 1U << MinAlignLog, true);
EXPECT_NE(P, nullptr);
for (scudo::uptr I = 0; I < Size; I++)
- EXPECT_EQ((reinterpret_cast<char *>(P))[I], 0);
+ ASSERT_EQ((reinterpret_cast<char *>(P))[I], 0);
+ memset(P, 0xaa, Size);
+ Allocator->deallocate(P, Origin, Size);
+ }
+ }
+ Allocator->releaseToOS();
+
+ // Ensure that specifying ZeroContents returns a zero'd out block.
+ Allocator->setFillContents(scudo::ZeroFill);
+ for (scudo::uptr SizeLog = 0U; SizeLog <= 20U; SizeLog++) {
+ for (scudo::uptr Delta = 0U; Delta <= 4U; Delta++) {
+ const scudo::uptr Size = (1U << SizeLog) + Delta * 128U;
+ void *P = Allocator->allocate(Size, Origin, 1U << MinAlignLog, false);
+ EXPECT_NE(P, nullptr);
+ for (scudo::uptr I = 0; I < Size; I++)
+ ASSERT_EQ((reinterpret_cast<char *>(P))[I], 0);
+ memset(P, 0xaa, Size);
+ Allocator->deallocate(P, Origin, Size);
+ }
+ }
+ Allocator->releaseToOS();
+
+ // Ensure that specifying PatternOrZeroFill returns a pattern-filled block in
+ // the primary allocator, and either pattern or zero filled block in the
+ // secondary.
+ Allocator->setFillContents(scudo::PatternOrZeroFill);
+ for (scudo::uptr SizeLog = 0U; SizeLog <= 20U; SizeLog++) {
+ for (scudo::uptr Delta = 0U; Delta <= 4U; Delta++) {
+ const scudo::uptr Size = (1U << SizeLog) + Delta * 128U;
+ void *P = Allocator->allocate(Size, Origin, 1U << MinAlignLog, false);
+ EXPECT_NE(P, nullptr);
+ for (scudo::uptr I = 0; I < Size; I++) {
+ unsigned char V = (reinterpret_cast<unsigned char *>(P))[I];
+ if (AllocatorT::PrimaryT::canAllocate(Size))
+ ASSERT_EQ(V, scudo::PatternFillByte);
+ else
+ ASSERT_TRUE(V == scudo::PatternFillByte || V == 0);
+ }
memset(P, 0xaa, Size);
Allocator->deallocate(P, Origin, Size);
}
diff --git a/compiler-rt/lib/scudo/standalone/wrappers_c.inc b/compiler-rt/lib/scudo/standalone/wrappers_c.inc
index 765d7daa349d..4396dfc50d1d 100644
--- a/compiler-rt/lib/scudo/standalone/wrappers_c.inc
+++ b/compiler-rt/lib/scudo/standalone/wrappers_c.inc
@@ -228,4 +228,19 @@ SCUDO_PREFIX(malloc_set_track_allocation_stacks)(int track) {
SCUDO_ALLOCATOR.setTrackAllocationStacks(track);
}
+// Sets whether scudo zero-initializes all allocated memory. The program must
+// be single threaded at the point when the function is called.
+INTERFACE WEAK void SCUDO_PREFIX(malloc_set_zero_contents)(int zero_contents) {
+ SCUDO_ALLOCATOR.setFillContents(zero_contents ? scudo::ZeroFill
+ : scudo::NoFill);
+}
+
+// Sets whether scudo pattern-initializes all allocated memory. The program must
+// be single threaded at the point when the function is called.
+INTERFACE WEAK void
+SCUDO_PREFIX(malloc_set_pattern_fill_contents)(int pattern_fill_contents) {
+ SCUDO_ALLOCATOR.setFillContents(
+ pattern_fill_contents ? scudo::PatternOrZeroFill : scudo::NoFill);
+}
+
} // extern "C"
More information about the llvm-commits
mailing list