[llvm-branch-commits] [scudo] Allow to resize allocation ring buffer (PR #82683)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Feb 22 12:34:24 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Florian Mayer (fmayer)

<details>
<summary>Changes</summary>



---
Full diff: https://github.com/llvm/llvm-project/pull/82683.diff


4 Files Affected:

- (modified) compiler-rt/lib/scudo/standalone/combined.h (+34-10) 
- (modified) compiler-rt/lib/scudo/standalone/include/scudo/interface.h (+2) 
- (modified) compiler-rt/lib/scudo/standalone/tests/combined_test.cpp (+27) 
- (modified) compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp (+4) 


``````````diff
diff --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h
index 79b5891fd35869..479e49c328e3d7 100644
--- a/compiler-rt/lib/scudo/standalone/combined.h
+++ b/compiler-rt/lib/scudo/standalone/combined.h
@@ -174,9 +174,11 @@ class Allocator {
         static_cast<uptr>(getFlags()->quarantine_size_kb << 10),
         static_cast<uptr>(getFlags()->thread_local_quarantine_size_kb << 10));
 
-    mapAndInitializeRingBuffer();
+    mapAndInitializeRingBuffer(getFlags()->allocation_ring_buffer_size);
   }
 
+  bool resizeRingBuffer(int Size) { return mapAndInitializeRingBuffer(Size); }
+
   // Initialize the embedded GWP-ASan instance. Requires the main allocator to
   // be functional, best called from PostInitCallback.
   void initGwpAsan() {
@@ -1531,11 +1533,15 @@ class Allocator {
         RBEntryStart)[N];
   }
 
-  void mapAndInitializeRingBuffer() {
-    if (getFlags()->allocation_ring_buffer_size <= 0)
-      return;
-    u32 AllocationRingBufferSize =
-        static_cast<u32>(getFlags()->allocation_ring_buffer_size);
+  bool mapAndInitializeRingBuffer(int RingBufferSize) {
+    if (RingBufferSize < 0 ||
+        static_cast<unsigned int>(RingBufferSize) >= UINT32_MAX)
+      return false;
+    if (RingBufferSize == 0) {
+      swapOutRingBuffer(nullptr);
+      return true;
+    }
+    u32 AllocationRingBufferSize = static_cast<u32>(RingBufferSize);
 
     // We store alloc and free stacks for each entry.
     constexpr u32 kStacksPerRingBufferEntry = 2;
@@ -1555,11 +1561,11 @@ class Allocator {
                   UINTPTR_MAX);
 
     if (AllocationRingBufferSize > kMaxU32Pow2 / kStacksPerRingBufferEntry)
-      return;
+      return false;
     u32 TabSize = static_cast<u32>(roundUpPowerOfTwo(kStacksPerRingBufferEntry *
                                                      AllocationRingBufferSize));
     if (TabSize > UINT32_MAX / kFramesPerStack)
-      return;
+      return false;
     u32 RingSize = static_cast<u32>(TabSize * kFramesPerStack);
     DCHECK(isPowerOfTwo(RingSize));
 
@@ -1585,12 +1591,30 @@ class Allocator {
     RB->StackDepotSize = StackDepotSize;
     RB->RawStackDepotMap = DepotMap;
 
-    atomic_store(&RingBufferAddress, reinterpret_cast<uptr>(RB),
-                 memory_order_release);
+    swapOutRingBuffer(RB);
     static_assert(sizeof(AllocationRingBuffer) %
                           alignof(typename AllocationRingBuffer::Entry) ==
                       0,
                   "invalid alignment");
+    return true;
+  }
+
+  void swapOutRingBuffer(AllocationRingBuffer *NewRB) {
+    AllocationRingBuffer *PrevRB = reinterpret_cast<AllocationRingBuffer *>(
+        atomic_exchange(&RingBufferAddress, reinterpret_cast<uptr>(NewRB),
+                        memory_order_acq_rel));
+    if (PrevRB) {
+      auto RawStackDepotMap = PrevRB->RawStackDepotMap;
+      if (RawStackDepotMap.isAllocated()) {
+        RawStackDepotMap.releaseAndZeroPagesToOS(
+            RawStackDepotMap.getBase(), RawStackDepotMap.getCapacity());
+      }
+      auto RawRingBufferMap = PrevRB->RawRingBufferMap;
+      if (RawRingBufferMap.isAllocated()) {
+        RawRingBufferMap.releaseAndZeroPagesToOS(
+            RawRingBufferMap.getBase(), RawRingBufferMap.getCapacity());
+      }
+    }
   }
 
   void unmapRingBuffer() {
diff --git a/compiler-rt/lib/scudo/standalone/include/scudo/interface.h b/compiler-rt/lib/scudo/standalone/include/scudo/interface.h
index a2dedea910cc08..8aca56b7172d9f 100644
--- a/compiler-rt/lib/scudo/standalone/include/scudo/interface.h
+++ b/compiler-rt/lib/scudo/standalone/include/scudo/interface.h
@@ -123,6 +123,8 @@ size_t __scudo_get_region_info_size(void);
 const char *__scudo_get_ring_buffer_addr(void);
 size_t __scudo_get_ring_buffer_size(void);
 
+bool __scudo_resize_ring_buffer(int);
+
 #ifndef M_DECAY_TIME
 #define M_DECAY_TIME -100
 #endif
diff --git a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
index 13d627b116809b..7e7a0e59cfe6d0 100644
--- a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
@@ -915,6 +915,33 @@ SCUDO_TYPED_TEST(ScudoCombinedTest, StackDepot) {
   EXPECT_EQ(Depot->at(RingPosPtr + 2), 3u);
 }
 
+SCUDO_TYPED_TEST(ScudoCombinedTest, ResizeRingBuffer) {
+  auto *Allocator = this->Allocator.get();
+  auto Size = static_cast<int>(Allocator->getRingBufferSize());
+  auto DepotSize = Allocator->getStackDepotSize();
+  ASSERT_GT(Size, 0);
+  ASSERT_TRUE(Allocator->resizeRingBuffer(Size + 1024));
+  EXPECT_GT(Allocator->getRingBufferSize(), Size);
+  EXPECT_GT(Allocator->getStackDepotSize(), DepotSize);
+}
+
+SCUDO_TYPED_TEST(ScudoCombinedTest, ResizeRingBufferToZero) {
+  auto *Allocator = this->Allocator.get();
+  const char *PrevRB = Allocator->getRingBufferAddress();
+  auto PrevRBSize = Allocator->getRingBufferSize();
+  ASSERT_TRUE(Allocator->resizeRingBuffer(0));
+  EXPECT_EQ(Allocator->getRingBufferSize(), 0);
+  EXPECT_EQ(Allocator->getStackDepotSize(), 0);
+  EXPECT_EQ(Allocator->getStackDepotAddress(), nullptr);
+  EXPECT_EQ(Allocator->getRingBufferAddress(), nullptr);
+  // Make sure the old buffer is still accessible without a segfault.
+  // We DONTNEED the buffer, so we free the underlying pages, but we keep the
+  // VMA around to prevent races.
+  ASSERT_NE(PrevRB, nullptr);
+  ASSERT_GT(PrevRBSize, 0);
+  const_cast<volatile const char *>(PrevRB)[PrevRBSize - 1];
+}
+
 #if SCUDO_CAN_USE_PRIMARY64
 #if SCUDO_TRUSTY
 
diff --git a/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp b/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
index e9d8c1e8d3db2f..004c9b9ef36cf6 100644
--- a/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
+++ b/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
@@ -72,4 +72,8 @@ INTERFACE size_t __scudo_get_ring_buffer_size() {
   return Allocator.getRingBufferSize();
 }
 
+INTERFACE bool __scudo_resize_ring_buffer(int new_size) {
+  return Allocator.resizeRingBuffer(new_size);
+}
+
 #endif // SCUDO_ANDROID && _BIONIC

``````````

</details>


https://github.com/llvm/llvm-project/pull/82683


More information about the llvm-branch-commits mailing list