[compiler-rt] 4f76810 - [scudo] Detach the hooks from Scudo's internal implementation

Chia-hung Duan via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 25 09:22:10 PDT 2023


Author: Chia-hung Duan
Date: 2023-08-25T16:19:56Z
New Revision: 4f76810d4860d851f069aa0caca24c54ab698c3b

URL: https://github.com/llvm/llvm-project/commit/4f76810d4860d851f069aa0caca24c54ab698c3b
DIFF: https://github.com/llvm/llvm-project/commit/4f76810d4860d851f069aa0caca24c54ab698c3b.diff

LOG: [scudo] Detach the hooks from Scudo's internal implementation

Move the invocation of hooks from Scudo internal to wrapper_c.cpp and
wrapper_c_bionic.cpp respectively. Therefore, Scudo's core algorithm
doesnt need to worry about the reentrant of hooks and leave the caring
of reentrant to the hook users.

Reviewed By: hctim, cferris, chelfi

Differential Revision: https://reviews.llvm.org/D152188

Added: 
    

Modified: 
    compiler-rt/lib/scudo/standalone/combined.h
    compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
    compiler-rt/lib/scudo/standalone/tests/wrappers_c_test.cpp
    compiler-rt/lib/scudo/standalone/tests/wrappers_cpp_test.cpp
    compiler-rt/lib/scudo/standalone/wrappers_c.cpp
    compiler-rt/lib/scudo/standalone/wrappers_c.inc
    compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
    compiler-rt/lib/scudo/standalone/wrappers_cpp.cpp

Removed: 
    compiler-rt/lib/scudo/standalone/tests/scudo_hooks_test.cpp


################################################################################
diff  --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h
index e1db7a70301184..8cc84adcd4843b 100644
--- a/compiler-rt/lib/scudo/standalone/combined.h
+++ b/compiler-rt/lib/scudo/standalone/combined.h
@@ -329,8 +329,6 @@ class Allocator {
 #ifdef GWP_ASAN_HOOKS
     if (UNLIKELY(GuardedAlloc.shouldSample())) {
       if (void *Ptr = GuardedAlloc.allocate(Size, Alignment)) {
-        if (UNLIKELY(&__scudo_allocate_hook))
-          __scudo_allocate_hook(Ptr, Size);
         Stats.lock();
         Stats.add(StatAllocated, GuardedAllocSlotSize);
         Stats.sub(StatFree, GuardedAllocSlotSize);
@@ -535,9 +533,6 @@ class Allocator {
         Chunk::SizeOrUnusedBytesMask;
     Chunk::storeHeader(Cookie, Ptr, &Header);
 
-    if (UNLIKELY(&__scudo_allocate_hook))
-      __scudo_allocate_hook(TaggedPtr, Size);
-
     return TaggedPtr;
   }
 
@@ -551,9 +546,6 @@ class Allocator {
     // being destroyed properly. Any other heap operation will do a full init.
     initThreadMaybe(/*MinimalInit=*/true);
 
-    if (UNLIKELY(&__scudo_deallocate_hook))
-      __scudo_deallocate_hook(Ptr);
-
     if (UNLIKELY(!Ptr))
       return;
 
@@ -697,8 +689,6 @@ class Allocator {
     void *NewPtr = allocate(NewSize, Chunk::Origin::Malloc, Alignment);
     if (LIKELY(NewPtr)) {
       memcpy(NewPtr, OldTaggedPtr, Min(NewSize, OldSize));
-      if (UNLIKELY(&__scudo_deallocate_hook))
-        __scudo_deallocate_hook(OldTaggedPtr);
       quarantineOrDeallocateChunk(Options, OldTaggedPtr, &OldHeader, OldSize);
     }
     return NewPtr;

diff  --git a/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt b/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
index cbb85ce3ec2e20..71ad3830c88ca3 100644
--- a/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
+++ b/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
@@ -137,11 +137,3 @@ set(SCUDO_CXX_UNIT_TEST_SOURCES
 add_scudo_unittest(ScudoCxxUnitTest
   SOURCES ${SCUDO_CXX_UNIT_TEST_SOURCES}
   ADDITIONAL_RTOBJECTS RTScudoStandaloneCWrappers RTScudoStandaloneCxxWrappers)
-
-set(SCUDO_HOOKS_UNIT_TEST_SOURCES
-  scudo_hooks_test.cpp
-  scudo_unit_test_main.cpp
-  )
-
-add_scudo_unittest(ScudoHooksUnitTest
-  SOURCES ${SCUDO_HOOKS_UNIT_TEST_SOURCES})

diff  --git a/compiler-rt/lib/scudo/standalone/tests/scudo_hooks_test.cpp b/compiler-rt/lib/scudo/standalone/tests/scudo_hooks_test.cpp
deleted file mode 100644
index 7184ec12a8bb30..00000000000000
--- a/compiler-rt/lib/scudo/standalone/tests/scudo_hooks_test.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-//===-- scudo_hooks_test.cpp ------------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "tests/scudo_unit_test.h"
-
-#include "allocator_config.h"
-#include "combined.h"
-
-namespace {
-void *LastAllocatedPtr = nullptr;
-size_t LastRequestSize = 0;
-void *LastDeallocatedPtr = nullptr;
-} // namespace
-
-// Scudo defines weak symbols that can be defined by a client binary
-// to register callbacks at key points in the allocation timeline.  In
-// order to enforce those invariants, we provide definitions that
-// update some global state every time they are called, so that tests
-// can inspect their effects.  An unfortunate side effect of this
-// setup is that because those symbols are part of the binary, they
-// can't be selectively enabled; that means that they will get called
-// on unrelated tests in the same compilation unit. To mitigate this
-// issue, we insulate those tests in a separate compilation unit.
-extern "C" {
-__attribute__((visibility("default"))) void __scudo_allocate_hook(void *Ptr,
-                                                                  size_t Size) {
-  LastAllocatedPtr = Ptr;
-  LastRequestSize = Size;
-}
-__attribute__((visibility("default"))) void __scudo_deallocate_hook(void *Ptr) {
-  LastDeallocatedPtr = Ptr;
-}
-}
-
-// Simple check that allocation callbacks, when registered, are called:
-//   1) __scudo_allocate_hook is called when allocating.
-//   2) __scudo_deallocate_hook is called when deallocating.
-//   3) Both hooks are called when reallocating.
-//   4) Neither are called for a no-op reallocation.
-TEST(ScudoHooksTest, AllocateHooks) {
-  scudo::Allocator<scudo::DefaultConfig> Allocator;
-  constexpr scudo::uptr DefaultSize = 16U;
-  constexpr scudo::Chunk::Origin Origin = scudo::Chunk::Origin::Malloc;
-
-  // Simple allocation and deallocation.
-  {
-    LastAllocatedPtr = nullptr;
-    LastRequestSize = 0;
-
-    void *Ptr = Allocator.allocate(DefaultSize, Origin);
-
-    EXPECT_EQ(Ptr, LastAllocatedPtr);
-    EXPECT_EQ(DefaultSize, LastRequestSize);
-
-    LastDeallocatedPtr = nullptr;
-
-    Allocator.deallocate(Ptr, Origin);
-
-    EXPECT_EQ(Ptr, LastDeallocatedPtr);
-  }
-
-  // Simple no-op, same size reallocation.
-  {
-    void *Ptr = Allocator.allocate(DefaultSize, Origin);
-
-    LastAllocatedPtr = nullptr;
-    LastRequestSize = 0;
-    LastDeallocatedPtr = nullptr;
-
-    void *NewPtr = Allocator.reallocate(Ptr, DefaultSize);
-
-    EXPECT_EQ(Ptr, NewPtr);
-    EXPECT_EQ(nullptr, LastAllocatedPtr);
-    EXPECT_EQ(0U, LastRequestSize);
-    EXPECT_EQ(nullptr, LastDeallocatedPtr);
-  }
-
-  // Reallocation in increasing size classes. This ensures that at
-  // least one of the reallocations will be meaningful.
-  {
-    void *Ptr = Allocator.allocate(0, Origin);
-
-    for (scudo::uptr ClassId = 1U;
-         ClassId <= scudo::DefaultConfig::Primary::SizeClassMap::LargestClassId;
-         ++ClassId) {
-      const scudo::uptr Size =
-          scudo::DefaultConfig::Primary::SizeClassMap::getSizeByClassId(
-              ClassId);
-
-      LastAllocatedPtr = nullptr;
-      LastRequestSize = 0;
-      LastDeallocatedPtr = nullptr;
-
-      void *NewPtr = Allocator.reallocate(Ptr, Size);
-
-      if (NewPtr != Ptr) {
-        EXPECT_EQ(NewPtr, LastAllocatedPtr);
-        EXPECT_EQ(Size, LastRequestSize);
-        EXPECT_EQ(Ptr, LastDeallocatedPtr);
-      } else {
-        EXPECT_EQ(nullptr, LastAllocatedPtr);
-        EXPECT_EQ(0U, LastRequestSize);
-        EXPECT_EQ(nullptr, LastDeallocatedPtr);
-      }
-
-      Ptr = NewPtr;
-    }
-  }
-}

diff  --git a/compiler-rt/lib/scudo/standalone/tests/wrappers_c_test.cpp b/compiler-rt/lib/scudo/standalone/tests/wrappers_c_test.cpp
index c921da980cad48..d0cc0fa3c6508c 100644
--- a/compiler-rt/lib/scudo/standalone/tests/wrappers_c_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/wrappers_c_test.cpp
@@ -37,6 +37,16 @@
 #define HAVE_VALLOC 1
 #endif
 
+struct AllocContext {
+  void *Ptr;
+  size_t Size;
+};
+struct DeallocContext {
+  void *Ptr;
+};
+static AllocContext AC;
+static DeallocContext DC;
+
 extern "C" {
 void malloc_enable(void);
 void malloc_disable(void);
@@ -45,6 +55,15 @@ int malloc_iterate(uintptr_t base, size_t size,
                    void *arg);
 void *valloc(size_t size);
 void *pvalloc(size_t size);
+
+__attribute__((visibility("default"))) void __scudo_allocate_hook(void *Ptr,
+                                                                  size_t Size) {
+  AC.Ptr = Ptr;
+  AC.Size = Size;
+}
+__attribute__((visibility("default"))) void __scudo_deallocate_hook(void *Ptr) {
+  DC.Ptr = Ptr;
+}
 }
 
 // Note that every C allocation function in the test binary will be fulfilled
@@ -64,6 +83,8 @@ TEST(ScudoWrappersCDeathTest, Malloc) {
   EXPECT_NE(P, nullptr);
   EXPECT_LE(Size, malloc_usable_size(P));
   EXPECT_EQ(reinterpret_cast<uintptr_t>(P) % FIRST_32_SECOND_64(8U, 16U), 0U);
+  EXPECT_EQ(P, AC.Ptr);
+  EXPECT_EQ(Size, AC.Size);
 
   // An update to this warning in Clang now triggers in this line, but it's ok
   // because the check is expecting a bad pointer and should fail.
@@ -78,6 +99,7 @@ TEST(ScudoWrappersCDeathTest, Malloc) {
 #endif
 
   free(P);
+  EXPECT_EQ(P, DC.Ptr);
   EXPECT_DEATH(free(P), "");
 
   P = malloc(0U);
@@ -93,9 +115,12 @@ TEST(ScudoWrappersCTest, Calloc) {
   void *P = calloc(1U, Size);
   EXPECT_NE(P, nullptr);
   EXPECT_LE(Size, malloc_usable_size(P));
+  EXPECT_EQ(P, AC.Ptr);
+  EXPECT_EQ(Size, AC.Size);
   for (size_t I = 0; I < Size; I++)
     EXPECT_EQ((reinterpret_cast<uint8_t *>(P))[I], 0U);
   free(P);
+  EXPECT_EQ(P, DC.Ptr);
 
   P = calloc(1U, 0U);
   EXPECT_NE(P, nullptr);
@@ -146,14 +171,20 @@ TEST(ScudoWrappersCTest, Memalign) {
     EXPECT_NE(P, nullptr);
     EXPECT_LE(Size, malloc_usable_size(P));
     EXPECT_EQ(reinterpret_cast<uintptr_t>(P) % Alignment, 0U);
+    EXPECT_EQ(P, AC.Ptr);
+    EXPECT_EQ(Size, AC.Size);
     free(P);
+    EXPECT_EQ(P, DC.Ptr);
 
     P = nullptr;
     EXPECT_EQ(posix_memalign(&P, Alignment, Size), 0);
     EXPECT_NE(P, nullptr);
     EXPECT_LE(Size, malloc_usable_size(P));
     EXPECT_EQ(reinterpret_cast<uintptr_t>(P) % Alignment, 0U);
+    EXPECT_EQ(P, AC.Ptr);
+    EXPECT_EQ(Size, AC.Size);
     free(P);
+    EXPECT_EQ(P, DC.Ptr);
   }
 
   EXPECT_EQ(memalign(4096U, SIZE_MAX), nullptr);
@@ -165,7 +196,10 @@ TEST(ScudoWrappersCTest, Memalign) {
     for (size_t Alignment = 0U; Alignment <= 128U; Alignment++) {
       P = memalign(Alignment, 1024U);
       EXPECT_NE(P, nullptr);
+      EXPECT_EQ(P, AC.Ptr);
+      EXPECT_EQ(Size, AC.Size);
       free(P);
+      EXPECT_EQ(P, DC.Ptr);
     }
   }
 }
@@ -176,7 +210,10 @@ TEST(ScudoWrappersCTest, AlignedAlloc) {
   EXPECT_NE(P, nullptr);
   EXPECT_LE(Alignment * 4U, malloc_usable_size(P));
   EXPECT_EQ(reinterpret_cast<uintptr_t>(P) % Alignment, 0U);
+  EXPECT_EQ(P, AC.Ptr);
+  EXPECT_EQ(Alignment * 4U, AC.Size);
   free(P);
+  EXPECT_EQ(P, DC.Ptr);
 
   errno = 0;
   P = aligned_alloc(Alignment, Size);
@@ -186,31 +223,52 @@ TEST(ScudoWrappersCTest, AlignedAlloc) {
 
 TEST(ScudoWrappersCDeathTest, Realloc) {
   // realloc(nullptr, N) is malloc(N)
-  void *P = realloc(nullptr, 0U);
+  void *P = realloc(nullptr, Size);
   EXPECT_NE(P, nullptr);
+  EXPECT_EQ(P, AC.Ptr);
+  EXPECT_EQ(Size, AC.Size);
   free(P);
+  EXPECT_EQ(P, DC.Ptr);
 
   P = malloc(Size);
   EXPECT_NE(P, nullptr);
   // realloc(P, 0U) is free(P) and returns nullptr
   EXPECT_EQ(realloc(P, 0U), nullptr);
+  EXPECT_EQ(P, DC.Ptr);
 
   P = malloc(Size);
   EXPECT_NE(P, nullptr);
   EXPECT_LE(Size, malloc_usable_size(P));
   memset(P, 0x42, Size);
 
+  AC.Ptr = reinterpret_cast<void *>(0xdeadbeef);
+  void *OldP = P;
   P = realloc(P, Size * 2U);
   EXPECT_NE(P, nullptr);
   EXPECT_LE(Size * 2U, malloc_usable_size(P));
   for (size_t I = 0; I < Size; I++)
     EXPECT_EQ(0x42, (reinterpret_cast<uint8_t *>(P))[I]);
+  if (OldP == P) {
+    EXPECT_EQ(AC.Ptr, reinterpret_cast<void *>(0xdeadbeef));
+  } else {
+    EXPECT_EQ(P, AC.Ptr);
+    EXPECT_EQ(Size * 2U, AC.Size);
+    EXPECT_EQ(OldP, DC.Ptr);
+  }
 
+  AC.Ptr = reinterpret_cast<void *>(0xdeadbeef);
+  OldP = P;
   P = realloc(P, Size / 2U);
   EXPECT_NE(P, nullptr);
   EXPECT_LE(Size / 2U, malloc_usable_size(P));
   for (size_t I = 0; I < Size / 2U; I++)
     EXPECT_EQ(0x42, (reinterpret_cast<uint8_t *>(P))[I]);
+  if (OldP == P) {
+    EXPECT_EQ(AC.Ptr, reinterpret_cast<void *>(0xdeadbeef));
+  } else {
+    EXPECT_EQ(P, AC.Ptr);
+    EXPECT_EQ(Size / 2U, AC.Size);
+  }
   free(P);
 
   EXPECT_DEATH(P = realloc(P, Size), "");
@@ -273,7 +331,11 @@ TEST(ScudoWrappersCTest, OtherAlloc) {
   EXPECT_NE(P, nullptr);
   EXPECT_EQ(reinterpret_cast<uintptr_t>(P) & (PageSize - 1), 0U);
   EXPECT_LE(PageSize, malloc_usable_size(P));
+  EXPECT_EQ(P, AC.Ptr);
+  // Size will be rounded up to PageSize.
+  EXPECT_EQ(PageSize, AC.Size);
   free(P);
+  EXPECT_EQ(P, DC.Ptr);
 
   EXPECT_EQ(pvalloc(SIZE_MAX), nullptr);
 

diff  --git a/compiler-rt/lib/scudo/standalone/tests/wrappers_cpp_test.cpp b/compiler-rt/lib/scudo/standalone/tests/wrappers_cpp_test.cpp
index 987e4099aa77dd..654bf547317809 100644
--- a/compiler-rt/lib/scudo/standalone/tests/wrappers_cpp_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/wrappers_cpp_test.cpp
@@ -24,47 +24,81 @@
 #define SKIP_MISMATCH_TESTS 0
 #endif
 
+struct AllocContext {
+  void *Ptr;
+  size_t Size;
+};
+struct DeallocContext {
+  void *Ptr;
+};
+static AllocContext AC;
+static DeallocContext DC;
+
 void operator delete(void *, size_t) noexcept;
 void operator delete[](void *, size_t) noexcept;
 
+extern "C" {
+__attribute__((visibility("default"))) void __scudo_allocate_hook(void *Ptr,
+                                                                  size_t Size) {
+  AC.Ptr = Ptr;
+  AC.Size = Size;
+}
+__attribute__((visibility("default"))) void __scudo_deallocate_hook(void *Ptr) {
+  DC.Ptr = Ptr;
+}
+}
 // Note that every Cxx allocation function in the test binary will be fulfilled
 // by Scudo. See the comment in the C counterpart of this file.
 
 template <typename T> static void testCxxNew() {
   T *P = new T;
   EXPECT_NE(P, nullptr);
+  EXPECT_EQ(P, AC.Ptr);
+  EXPECT_EQ(sizeof(T), AC.Size);
   memset(P, 0x42, sizeof(T));
   EXPECT_DEATH(delete[] P, "");
   delete P;
+  EXPECT_EQ(P, DC.Ptr);
   EXPECT_DEATH(delete P, "");
 
   P = new T;
   EXPECT_NE(P, nullptr);
   memset(P, 0x42, sizeof(T));
   operator delete(P, sizeof(T));
+  EXPECT_EQ(P, DC.Ptr);
 
   P = new (std::nothrow) T;
+  EXPECT_EQ(P, AC.Ptr);
+  EXPECT_EQ(sizeof(T), AC.Size);
   EXPECT_NE(P, nullptr);
   memset(P, 0x42, sizeof(T));
   delete P;
+  EXPECT_EQ(P, DC.Ptr);
 
   const size_t N = 16U;
   T *A = new T[N];
   EXPECT_NE(A, nullptr);
+  EXPECT_EQ(A, AC.Ptr);
+  EXPECT_EQ(sizeof(T) * N, AC.Size);
   memset(A, 0x42, sizeof(T) * N);
   EXPECT_DEATH(delete A, "");
   delete[] A;
+  EXPECT_EQ(A, DC.Ptr);
   EXPECT_DEATH(delete[] A, "");
 
   A = new T[N];
   EXPECT_NE(A, nullptr);
   memset(A, 0x42, sizeof(T) * N);
   operator delete[](A, sizeof(T) * N);
+  EXPECT_EQ(A, DC.Ptr);
 
   A = new (std::nothrow) T[N];
+  EXPECT_EQ(A, AC.Ptr);
+  EXPECT_EQ(sizeof(T) * N, AC.Size);
   EXPECT_NE(A, nullptr);
   memset(A, 0x42, sizeof(T) * N);
   delete[] A;
+  EXPECT_EQ(A, DC.Ptr);
 }
 
 class Pixel {

diff  --git a/compiler-rt/lib/scudo/standalone/wrappers_c.cpp b/compiler-rt/lib/scudo/standalone/wrappers_c.cpp
index b4d51be716ccef..0b204271c81ce7 100644
--- a/compiler-rt/lib/scudo/standalone/wrappers_c.cpp
+++ b/compiler-rt/lib/scudo/standalone/wrappers_c.cpp
@@ -12,6 +12,7 @@
 #if !SCUDO_ANDROID || !_BIONIC
 
 #include "allocator_config.h"
+#include "scudo/interface.h"
 #include "wrappers_c.h"
 #include "wrappers_c_checks.h"
 

diff  --git a/compiler-rt/lib/scudo/standalone/wrappers_c.inc b/compiler-rt/lib/scudo/standalone/wrappers_c.inc
index a475927b9f51af..0bd5eddfa0b1c1 100644
--- a/compiler-rt/lib/scudo/standalone/wrappers_c.inc
+++ b/compiler-rt/lib/scudo/standalone/wrappers_c.inc
@@ -17,6 +17,16 @@
 #define SCUDO_MALLOC_ALIGNMENT FIRST_32_SECOND_64(8U, 16U)
 #endif
 
+static void reportAllocation(void *ptr, size_t size) {
+  if (__scudo_allocate_hook && ptr)
+    __scudo_allocate_hook(ptr, size);
+}
+
+static void reportDeallocation(void *ptr) {
+  if (__scudo_deallocate_hook)
+    __scudo_deallocate_hook(ptr);
+}
+
 extern "C" {
 
 INTERFACE WEAK void *SCUDO_PREFIX(calloc)(size_t nmemb, size_t size) {
@@ -28,11 +38,14 @@ INTERFACE WEAK void *SCUDO_PREFIX(calloc)(size_t nmemb, size_t size) {
     }
     scudo::reportCallocOverflow(nmemb, size);
   }
-  return scudo::setErrnoOnNull(SCUDO_ALLOCATOR.allocate(
-      Product, scudo::Chunk::Origin::Malloc, SCUDO_MALLOC_ALIGNMENT, true));
+  void *Ptr = SCUDO_ALLOCATOR.allocate(Product, scudo::Chunk::Origin::Malloc,
+                                       SCUDO_MALLOC_ALIGNMENT, true);
+  reportAllocation(Ptr, Product);
+  return scudo::setErrnoOnNull(Ptr);
 }
 
 INTERFACE WEAK void SCUDO_PREFIX(free)(void *ptr) {
+  reportDeallocation(ptr);
   SCUDO_ALLOCATOR.deallocate(ptr, scudo::Chunk::Origin::Malloc);
 }
 
@@ -75,8 +88,10 @@ INTERFACE WEAK struct __scudo_mallinfo2 SCUDO_PREFIX(mallinfo2)(void) {
 #endif
 
 INTERFACE WEAK void *SCUDO_PREFIX(malloc)(size_t size) {
-  return scudo::setErrnoOnNull(SCUDO_ALLOCATOR.allocate(
-      size, scudo::Chunk::Origin::Malloc, SCUDO_MALLOC_ALIGNMENT));
+  void *Ptr = SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Malloc,
+                                       SCUDO_MALLOC_ALIGNMENT);
+  reportAllocation(Ptr, size);
+  return scudo::setErrnoOnNull(Ptr);
 }
 
 #if SCUDO_ANDROID
@@ -105,8 +120,10 @@ INTERFACE WEAK void *SCUDO_PREFIX(memalign)(size_t alignment, size_t size) {
       scudo::reportAlignmentNotPowerOfTwo(alignment);
     }
   }
-  return SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Memalign,
-                                  alignment);
+  void *Ptr =
+      SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Memalign, alignment);
+  reportAllocation(Ptr, size);
+  return Ptr;
 }
 
 INTERFACE WEAK int SCUDO_PREFIX(posix_memalign)(void **memptr, size_t alignment,
@@ -120,6 +137,8 @@ INTERFACE WEAK int SCUDO_PREFIX(posix_memalign)(void **memptr, size_t alignment,
       SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Memalign, alignment);
   if (UNLIKELY(!Ptr))
     return ENOMEM;
+  reportAllocation(Ptr, size);
+
   *memptr = Ptr;
   return 0;
 }
@@ -134,26 +153,42 @@ INTERFACE WEAK void *SCUDO_PREFIX(pvalloc)(size_t size) {
     scudo::reportPvallocOverflow(size);
   }
   // pvalloc(0) should allocate one page.
-  return scudo::setErrnoOnNull(
+  void *Ptr =
       SCUDO_ALLOCATOR.allocate(size ? scudo::roundUp(size, PageSize) : PageSize,
-                               scudo::Chunk::Origin::Memalign, PageSize));
+                               scudo::Chunk::Origin::Memalign, PageSize);
+  reportAllocation(Ptr, scudo::roundUp(size, PageSize));
+
+  return scudo::setErrnoOnNull(Ptr);
 }
 
 INTERFACE WEAK void *SCUDO_PREFIX(realloc)(void *ptr, size_t size) {
-  if (!ptr)
-    return scudo::setErrnoOnNull(SCUDO_ALLOCATOR.allocate(
-        size, scudo::Chunk::Origin::Malloc, SCUDO_MALLOC_ALIGNMENT));
+  if (!ptr) {
+    void *Ptr = SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Malloc,
+                                         SCUDO_MALLOC_ALIGNMENT);
+    reportAllocation(Ptr, size);
+    return scudo::setErrnoOnNull(Ptr);
+  }
   if (size == 0) {
+    reportDeallocation(ptr);
     SCUDO_ALLOCATOR.deallocate(ptr, scudo::Chunk::Origin::Malloc);
     return nullptr;
   }
-  return scudo::setErrnoOnNull(
-      SCUDO_ALLOCATOR.reallocate(ptr, size, SCUDO_MALLOC_ALIGNMENT));
+
+  void *NewPtr = SCUDO_ALLOCATOR.reallocate(ptr, size, SCUDO_MALLOC_ALIGNMENT);
+  if (NewPtr != ptr) {
+    reportAllocation(NewPtr, size);
+    reportDeallocation(ptr);
+  }
+
+  return scudo::setErrnoOnNull(NewPtr);
 }
 
 INTERFACE WEAK void *SCUDO_PREFIX(valloc)(size_t size) {
-  return scudo::setErrnoOnNull(SCUDO_ALLOCATOR.allocate(
-      size, scudo::Chunk::Origin::Memalign, scudo::getPageSizeCached()));
+  void *Ptr = SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Memalign,
+                                       scudo::getPageSizeCached());
+  reportAllocation(Ptr, size);
+
+  return scudo::setErrnoOnNull(Ptr);
 }
 
 INTERFACE WEAK int SCUDO_PREFIX(malloc_iterate)(
@@ -234,8 +269,12 @@ INTERFACE WEAK void *SCUDO_PREFIX(aligned_alloc)(size_t alignment,
     }
     scudo::reportInvalidAlignedAllocAlignment(alignment, size);
   }
-  return scudo::setErrnoOnNull(
-      SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Malloc, alignment));
+
+  void *Ptr =
+      SCUDO_ALLOCATOR.allocate(size, scudo::Chunk::Origin::Malloc, alignment);
+  reportAllocation(Ptr, size);
+
+  return scudo::setErrnoOnNull(Ptr);
 }
 
 INTERFACE WEAK int SCUDO_PREFIX(malloc_info)(UNUSED int options, FILE *stream) {

diff  --git a/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp b/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
index 1b9fe67d920c36..db824e6f754737 100644
--- a/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
+++ b/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
@@ -12,6 +12,7 @@
 #if SCUDO_ANDROID && _BIONIC
 
 #include "allocator_config.h"
+#include "scudo/interface.h"
 #include "wrappers_c.h"
 #include "wrappers_c_checks.h"
 

diff  --git a/compiler-rt/lib/scudo/standalone/wrappers_cpp.cpp b/compiler-rt/lib/scudo/standalone/wrappers_cpp.cpp
index 374e36d72b3d9e..9ea2aaed1e7857 100644
--- a/compiler-rt/lib/scudo/standalone/wrappers_cpp.cpp
+++ b/compiler-rt/lib/scudo/standalone/wrappers_cpp.cpp
@@ -12,6 +12,7 @@
 #if !SCUDO_ANDROID || !_BIONIC
 
 #include "allocator_config.h"
+#include "scudo/interface.h"
 #include "wrappers_c.h"
 
 #include <stdint.h>
@@ -21,86 +22,124 @@ struct nothrow_t {};
 enum class align_val_t : size_t {};
 } // namespace std
 
+static void reportAllocation(void *ptr, size_t size) {
+  if (__scudo_allocate_hook && ptr)
+    __scudo_allocate_hook(ptr, size);
+}
+
+static void reportDeallocation(void *ptr) {
+  if (__scudo_deallocate_hook)
+    __scudo_deallocate_hook(ptr);
+}
+
 INTERFACE WEAK void *operator new(size_t size) {
-  return Allocator.allocate(size, scudo::Chunk::Origin::New);
+  void *Ptr = Allocator.allocate(size, scudo::Chunk::Origin::New);
+  reportAllocation(Ptr, size);
+  return Ptr;
 }
 INTERFACE WEAK void *operator new[](size_t size) {
-  return Allocator.allocate(size, scudo::Chunk::Origin::NewArray);
+  void *Ptr = Allocator.allocate(size, scudo::Chunk::Origin::NewArray);
+  reportAllocation(Ptr, size);
+  return Ptr;
 }
 INTERFACE WEAK void *operator new(size_t size,
                                   std::nothrow_t const &) NOEXCEPT {
-  return Allocator.allocate(size, scudo::Chunk::Origin::New);
+  void *Ptr = Allocator.allocate(size, scudo::Chunk::Origin::New);
+  reportAllocation(Ptr, size);
+  return Ptr;
 }
 INTERFACE WEAK void *operator new[](size_t size,
                                     std::nothrow_t const &) NOEXCEPT {
-  return Allocator.allocate(size, scudo::Chunk::Origin::NewArray);
+  void *Ptr = Allocator.allocate(size, scudo::Chunk::Origin::NewArray);
+  reportAllocation(Ptr, size);
+  return Ptr;
 }
 INTERFACE WEAK void *operator new(size_t size, std::align_val_t align) {
-  return Allocator.allocate(size, scudo::Chunk::Origin::New,
-                            static_cast<scudo::uptr>(align));
+  void *Ptr = Allocator.allocate(size, scudo::Chunk::Origin::New,
+                                 static_cast<scudo::uptr>(align));
+  reportAllocation(Ptr, size);
+  return Ptr;
 }
 INTERFACE WEAK void *operator new[](size_t size, std::align_val_t align) {
-  return Allocator.allocate(size, scudo::Chunk::Origin::NewArray,
-                            static_cast<scudo::uptr>(align));
+  void *Ptr = Allocator.allocate(size, scudo::Chunk::Origin::NewArray,
+                                 static_cast<scudo::uptr>(align));
+  reportAllocation(Ptr, size);
+  return Ptr;
 }
 INTERFACE WEAK void *operator new(size_t size, std::align_val_t align,
                                   std::nothrow_t const &) NOEXCEPT {
-  return Allocator.allocate(size, scudo::Chunk::Origin::New,
-                            static_cast<scudo::uptr>(align));
+  void *Ptr = Allocator.allocate(size, scudo::Chunk::Origin::New,
+                                 static_cast<scudo::uptr>(align));
+  reportAllocation(Ptr, size);
+  return Ptr;
 }
 INTERFACE WEAK void *operator new[](size_t size, std::align_val_t align,
                                     std::nothrow_t const &) NOEXCEPT {
-  return Allocator.allocate(size, scudo::Chunk::Origin::NewArray,
-                            static_cast<scudo::uptr>(align));
+  void *Ptr = Allocator.allocate(size, scudo::Chunk::Origin::NewArray,
+                                 static_cast<scudo::uptr>(align));
+  reportAllocation(Ptr, size);
+  return Ptr;
 }
 
 INTERFACE WEAK void operator delete(void *ptr) NOEXCEPT {
+  reportDeallocation(ptr);
   Allocator.deallocate(ptr, scudo::Chunk::Origin::New);
 }
 INTERFACE WEAK void operator delete[](void *ptr) NOEXCEPT {
+  reportDeallocation(ptr);
   Allocator.deallocate(ptr, scudo::Chunk::Origin::NewArray);
 }
 INTERFACE WEAK void operator delete(void *ptr,
                                     std::nothrow_t const &) NOEXCEPT {
+  reportDeallocation(ptr);
   Allocator.deallocate(ptr, scudo::Chunk::Origin::New);
 }
 INTERFACE WEAK void operator delete[](void *ptr,
                                       std::nothrow_t const &) NOEXCEPT {
+  reportDeallocation(ptr);
   Allocator.deallocate(ptr, scudo::Chunk::Origin::NewArray);
 }
 INTERFACE WEAK void operator delete(void *ptr, size_t size) NOEXCEPT {
+  reportDeallocation(ptr);
   Allocator.deallocate(ptr, scudo::Chunk::Origin::New, size);
 }
 INTERFACE WEAK void operator delete[](void *ptr, size_t size) NOEXCEPT {
+  reportDeallocation(ptr);
   Allocator.deallocate(ptr, scudo::Chunk::Origin::NewArray, size);
 }
 INTERFACE WEAK void operator delete(void *ptr,
                                     std::align_val_t align) NOEXCEPT {
+  reportDeallocation(ptr);
   Allocator.deallocate(ptr, scudo::Chunk::Origin::New, 0,
                        static_cast<scudo::uptr>(align));
 }
 INTERFACE WEAK void operator delete[](void *ptr,
                                       std::align_val_t align) NOEXCEPT {
+  reportDeallocation(ptr);
   Allocator.deallocate(ptr, scudo::Chunk::Origin::NewArray, 0,
                        static_cast<scudo::uptr>(align));
 }
 INTERFACE WEAK void operator delete(void *ptr, std::align_val_t align,
                                     std::nothrow_t const &) NOEXCEPT {
+  reportDeallocation(ptr);
   Allocator.deallocate(ptr, scudo::Chunk::Origin::New, 0,
                        static_cast<scudo::uptr>(align));
 }
 INTERFACE WEAK void operator delete[](void *ptr, std::align_val_t align,
                                       std::nothrow_t const &) NOEXCEPT {
+  reportDeallocation(ptr);
   Allocator.deallocate(ptr, scudo::Chunk::Origin::NewArray, 0,
                        static_cast<scudo::uptr>(align));
 }
 INTERFACE WEAK void operator delete(void *ptr, size_t size,
                                     std::align_val_t align) NOEXCEPT {
+  reportDeallocation(ptr);
   Allocator.deallocate(ptr, scudo::Chunk::Origin::New, size,
                        static_cast<scudo::uptr>(align));
 }
 INTERFACE WEAK void operator delete[](void *ptr, size_t size,
                                       std::align_val_t align) NOEXCEPT {
+  reportDeallocation(ptr);
   Allocator.deallocate(ptr, scudo::Chunk::Origin::NewArray, size,
                        static_cast<scudo::uptr>(align));
 }


        


More information about the llvm-commits mailing list