[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