[compiler-rt] 8885296 - [scudo] Add SCUDO_ENABLE_HOOKS to enable hooks at compilation time

Chia-hung Duan via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 28 15:16:38 PDT 2023


Author: Chia-hung Duan
Date: 2023-08-28T22:11:18Z
New Revision: 88852964ecae94be71e98e9881ed8ed182df8c0c

URL: https://github.com/llvm/llvm-project/commit/88852964ecae94be71e98e9881ed8ed182df8c0c
DIFF: https://github.com/llvm/llvm-project/commit/88852964ecae94be71e98e9881ed8ed182df8c0c.diff

LOG: [scudo] Add SCUDO_ENABLE_HOOKS to enable hooks at compilation time

Accessing the PLT entries of hooks can lead a certain amount of
performance overhead. This is observed on certain tasks which will do a
bunch of malloc/free and their throughputs are impacted by the null
check of hooks.

Also add SCUDO_ENABLE_HOOKS_TESTS to select if we want to run the hook
tests. On some platforms they may have different ways to run the
wrappers tests (end-to-end tests) and test the hooks along with the
wrappers tests may not be feasible. Provide an option to turn it ON/OFF.

By default, we only verify the hook behavior in the scudo standalone
tests if SCUDO_ENABLE_HOOKS is defined or COMPILER_RT_DEBUG is true.

Reviewed By: cferris, fabio-d

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

Added: 
    

Modified: 
    compiler-rt/lib/scudo/standalone/CMakeLists.txt
    compiler-rt/lib/scudo/standalone/platform.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: 
    


################################################################################
diff  --git a/compiler-rt/lib/scudo/standalone/CMakeLists.txt b/compiler-rt/lib/scudo/standalone/CMakeLists.txt
index a5d9a4651c2039..52c3a2e5a52956 100644
--- a/compiler-rt/lib/scudo/standalone/CMakeLists.txt
+++ b/compiler-rt/lib/scudo/standalone/CMakeLists.txt
@@ -25,7 +25,7 @@ append_list_if(COMPILER_RT_HAS_WNO_PEDANTIC -Wno-pedantic SCUDO_CFLAGS)
 append_list_if(COMPILER_RT_HAS_FNO_LTO_FLAG -fno-lto SCUDO_CFLAGS)
 
 if(COMPILER_RT_DEBUG)
-  list(APPEND SCUDO_CFLAGS -O0 -DSCUDO_DEBUG=1)
+  list(APPEND SCUDO_CFLAGS -O0 -DSCUDO_DEBUG=1 -DSCUDO_ENABLE_HOOKS=1)
 else()
   list(APPEND SCUDO_CFLAGS -O3)
 endif()

diff  --git a/compiler-rt/lib/scudo/standalone/platform.h b/compiler-rt/lib/scudo/standalone/platform.h
index 7504c9d142f990..b71a86be7669f3 100644
--- a/compiler-rt/lib/scudo/standalone/platform.h
+++ b/compiler-rt/lib/scudo/standalone/platform.h
@@ -73,6 +73,10 @@
 #endif
 #endif
 
+#ifndef SCUDO_ENABLE_HOOKS
+#define SCUDO_ENABLE_HOOKS 0
+#endif
+
 #ifndef SCUDO_MIN_ALIGNMENT_LOG
 // We force malloc-type functions to be aligned to std::max_align_t, but there
 // is no reason why the minimum alignment for all other functions can't be 8

diff  --git a/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt b/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
index 71ad3830c88ca3..e5d32f33d8cc4a 100644
--- a/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
+++ b/compiler-rt/lib/scudo/standalone/tests/CMakeLists.txt
@@ -19,7 +19,10 @@ set(SCUDO_UNITTEST_CFLAGS
   -Wno-mismatched-new-delete)
 
 if(COMPILER_RT_DEBUG)
-  list(APPEND SCUDO_UNITTEST_CFLAGS -DSCUDO_DEBUG=1)
+  list(APPEND SCUDO_UNITTEST_CFLAGS -DSCUDO_DEBUG=1 -DSCUDO_ENABLE_HOOKS=1)
+  if (NOT FUCHSIA)
+    list(APPEND SCUDO_UNITTEST_CFLAGS -DSCUDO_ENABLE_HOOKS_TESTS=1)
+  endif()
 endif()
 
 if(ANDROID)

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 d0cc0fa3c6508c..0e82813df8c0d5 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,23 @@
 #define HAVE_VALLOC 1
 #endif
 
+extern "C" {
+void malloc_enable(void);
+void malloc_disable(void);
+int malloc_iterate(uintptr_t base, size_t size,
+                   void (*callback)(uintptr_t base, size_t size, void *arg),
+                   void *arg);
+void *valloc(size_t size);
+void *pvalloc(size_t size);
+
+#ifndef SCUDO_ENABLE_HOOKS_TESTS
+#define SCUDO_ENABLE_HOOKS_TESTS 0
+#endif
+
+#if (SCUDO_ENABLE_HOOKS_TESTS == 1) && (SCUDO_ENABLE_HOOKS == 0)
+#error "Hooks tests should have hooks enabled as well!"
+#endif
+
 struct AllocContext {
   void *Ptr;
   size_t Size;
@@ -47,15 +64,7 @@ struct DeallocContext {
 static AllocContext AC;
 static DeallocContext DC;
 
-extern "C" {
-void malloc_enable(void);
-void malloc_disable(void);
-int malloc_iterate(uintptr_t base, size_t size,
-                   void (*callback)(uintptr_t base, size_t size, void *arg),
-                   void *arg);
-void *valloc(size_t size);
-void *pvalloc(size_t size);
-
+#if (SCUDO_ENABLE_HOOKS_TESTS == 1)
 __attribute__((visibility("default"))) void __scudo_allocate_hook(void *Ptr,
                                                                   size_t Size) {
   AC.Ptr = Ptr;
@@ -64,8 +73,35 @@ __attribute__((visibility("default"))) void __scudo_allocate_hook(void *Ptr,
 __attribute__((visibility("default"))) void __scudo_deallocate_hook(void *Ptr) {
   DC.Ptr = Ptr;
 }
+#endif // (SCUDO_ENABLE_HOOKS_TESTS == 1)
 }
 
+class ScudoWrappersCTest : public Test {
+protected:
+  void SetUp() override {
+    if (SCUDO_ENABLE_HOOKS && !SCUDO_ENABLE_HOOKS_TESTS)
+      printf("Hooks are enabled but hooks tests are disabled.\n");
+  }
+
+  void invalidateAllocHookPtrAs(UNUSED void *Ptr) {
+    if (SCUDO_ENABLE_HOOKS_TESTS)
+      AC.Ptr = Ptr;
+  }
+  void verifyAllocHookPtr(UNUSED void *Ptr) {
+    if (SCUDO_ENABLE_HOOKS_TESTS)
+      EXPECT_EQ(Ptr, AC.Ptr);
+  }
+  void verifyAllocHookSize(UNUSED size_t Size) {
+    if (SCUDO_ENABLE_HOOKS_TESTS)
+      EXPECT_EQ(Size, AC.Size);
+  }
+  void verifyDeallocHookPtr(UNUSED void *Ptr) {
+    if (SCUDO_ENABLE_HOOKS_TESTS)
+      EXPECT_EQ(Ptr, DC.Ptr);
+  }
+};
+using ScudoWrappersCDeathTest = ScudoWrappersCTest;
+
 // Note that every C allocation function in the test binary will be fulfilled
 // by Scudo (this includes the gtest APIs, etc.), which is a test by itself.
 // But this might also lead to unexpected side-effects, since the allocation and
@@ -78,13 +114,13 @@ __attribute__((visibility("default"))) void __scudo_deallocate_hook(void *Ptr) {
 
 static const size_t Size = 100U;
 
-TEST(ScudoWrappersCDeathTest, Malloc) {
+TEST_F(ScudoWrappersCDeathTest, Malloc) {
   void *P = malloc(Size);
   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);
+  verifyAllocHookPtr(P);
+  verifyAllocHookSize(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.
@@ -99,7 +135,7 @@ TEST(ScudoWrappersCDeathTest, Malloc) {
 #endif
 
   free(P);
-  EXPECT_EQ(P, DC.Ptr);
+  verifyDeallocHookPtr(P);
   EXPECT_DEATH(free(P), "");
 
   P = malloc(0U);
@@ -111,16 +147,16 @@ TEST(ScudoWrappersCDeathTest, Malloc) {
   EXPECT_EQ(errno, ENOMEM);
 }
 
-TEST(ScudoWrappersCTest, Calloc) {
+TEST_F(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);
+  verifyAllocHookPtr(P);
+  verifyAllocHookSize(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);
+  verifyDeallocHookPtr(P);
 
   P = calloc(1U, 0U);
   EXPECT_NE(P, nullptr);
@@ -141,7 +177,7 @@ TEST(ScudoWrappersCTest, Calloc) {
   EXPECT_EQ(errno, ENOMEM);
 }
 
-TEST(ScudoWrappersCTest, SmallAlign) {
+TEST_F(ScudoWrappersCTest, SmallAlign) {
   // Allocating pointers by the powers of 2 from 1 to 0x10000
   // Using powers of 2 due to memalign using powers of 2 and test more sizes
   constexpr size_t MaxSize = 0x10000;
@@ -162,7 +198,7 @@ TEST(ScudoWrappersCTest, SmallAlign) {
     free(ptr);
 }
 
-TEST(ScudoWrappersCTest, Memalign) {
+TEST_F(ScudoWrappersCTest, Memalign) {
   void *P;
   for (size_t I = FIRST_32_SECOND_64(2U, 3U); I <= 18U; I++) {
     const size_t Alignment = 1U << I;
@@ -171,20 +207,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);
+    verifyAllocHookPtr(P);
+    verifyAllocHookSize(Size);
     free(P);
-    EXPECT_EQ(P, DC.Ptr);
+    verifyDeallocHookPtr(P);
 
     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);
+    verifyAllocHookPtr(P);
+    verifyAllocHookSize(Size);
     free(P);
-    EXPECT_EQ(P, DC.Ptr);
+    verifyDeallocHookPtr(P);
   }
 
   EXPECT_EQ(memalign(4096U, SIZE_MAX), nullptr);
@@ -196,24 +232,24 @@ 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);
+      verifyAllocHookPtr(P);
+      verifyAllocHookSize(Size);
       free(P);
-      EXPECT_EQ(P, DC.Ptr);
+      verifyDeallocHookPtr(P);
     }
   }
 }
 
-TEST(ScudoWrappersCTest, AlignedAlloc) {
+TEST_F(ScudoWrappersCTest, AlignedAlloc) {
   const size_t Alignment = 4096U;
   void *P = aligned_alloc(Alignment, Alignment * 4U);
   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);
+  verifyAllocHookPtr(P);
+  verifyAllocHookSize(Alignment * 4U);
   free(P);
-  EXPECT_EQ(P, DC.Ptr);
+  verifyDeallocHookPtr(P);
 
   errno = 0;
   P = aligned_alloc(Alignment, Size);
@@ -221,27 +257,27 @@ TEST(ScudoWrappersCTest, AlignedAlloc) {
   EXPECT_EQ(errno, EINVAL);
 }
 
-TEST(ScudoWrappersCDeathTest, Realloc) {
+TEST_F(ScudoWrappersCDeathTest, Realloc) {
   // realloc(nullptr, N) is malloc(N)
   void *P = realloc(nullptr, Size);
   EXPECT_NE(P, nullptr);
-  EXPECT_EQ(P, AC.Ptr);
-  EXPECT_EQ(Size, AC.Size);
+  verifyAllocHookPtr(P);
+  verifyAllocHookSize(Size);
   free(P);
-  EXPECT_EQ(P, DC.Ptr);
+  verifyDeallocHookPtr(P);
 
   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);
+  verifyDeallocHookPtr(P);
 
   P = malloc(Size);
   EXPECT_NE(P, nullptr);
   EXPECT_LE(Size, malloc_usable_size(P));
   memset(P, 0x42, Size);
 
-  AC.Ptr = reinterpret_cast<void *>(0xdeadbeef);
+  invalidateAllocHookPtrAs(reinterpret_cast<void *>(0xdeadbeef));
   void *OldP = P;
   P = realloc(P, Size * 2U);
   EXPECT_NE(P, nullptr);
@@ -249,14 +285,14 @@ TEST(ScudoWrappersCDeathTest, Realloc) {
   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));
+    verifyAllocHookPtr(reinterpret_cast<void *>(0xdeadbeef));
   } else {
-    EXPECT_EQ(P, AC.Ptr);
-    EXPECT_EQ(Size * 2U, AC.Size);
-    EXPECT_EQ(OldP, DC.Ptr);
+    verifyAllocHookPtr(P);
+    verifyAllocHookSize(Size * 2U);
+    verifyDeallocHookPtr(OldP);
   }
 
-  AC.Ptr = reinterpret_cast<void *>(0xdeadbeef);
+  invalidateAllocHookPtrAs(reinterpret_cast<void *>(0xdeadbeef));
   OldP = P;
   P = realloc(P, Size / 2U);
   EXPECT_NE(P, nullptr);
@@ -264,10 +300,10 @@ TEST(ScudoWrappersCDeathTest, Realloc) {
   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));
+    verifyAllocHookPtr(reinterpret_cast<void *>(0xdeadbeef));
   } else {
-    EXPECT_EQ(P, AC.Ptr);
-    EXPECT_EQ(Size / 2U, AC.Size);
+    verifyAllocHookPtr(P);
+    verifyAllocHookSize(Size / 2U);
   }
   free(P);
 
@@ -302,7 +338,7 @@ TEST(ScudoWrappersCDeathTest, Realloc) {
 }
 
 #if !SCUDO_FUCHSIA
-TEST(ScudoWrappersCTest, MallOpt) {
+TEST_F(ScudoWrappersCTest, MallOpt) {
   errno = 0;
   EXPECT_EQ(mallopt(-1000, 1), 0);
   // mallopt doesn't set errno.
@@ -323,7 +359,7 @@ TEST(ScudoWrappersCTest, MallOpt) {
 }
 #endif
 
-TEST(ScudoWrappersCTest, OtherAlloc) {
+TEST_F(ScudoWrappersCTest, OtherAlloc) {
 #if HAVE_PVALLOC
   const size_t PageSize = static_cast<size_t>(sysconf(_SC_PAGESIZE));
 
@@ -331,11 +367,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);
+  verifyAllocHookPtr(P);
   // Size will be rounded up to PageSize.
-  EXPECT_EQ(PageSize, AC.Size);
+  verifyAllocHookSize(PageSize);
   free(P);
-  EXPECT_EQ(P, DC.Ptr);
+  verifyDeallocHookPtr(P);
 
   EXPECT_EQ(pvalloc(SIZE_MAX), nullptr);
 
@@ -351,7 +387,7 @@ TEST(ScudoWrappersCTest, OtherAlloc) {
 }
 
 #if !SCUDO_FUCHSIA
-TEST(ScudoWrappersCTest, MallInfo) {
+TEST_F(ScudoWrappersCTest, MallInfo) {
   // mallinfo is deprecated.
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -372,7 +408,7 @@ TEST(ScudoWrappersCTest, MallInfo) {
 #endif
 
 #if __GLIBC_PREREQ(2, 33)
-TEST(ScudoWrappersCTest, MallInfo2) {
+TEST_F(ScudoWrappersCTest, MallInfo2) {
   const size_t BypassQuarantineSize = 1024U;
   struct mallinfo2 MI = mallinfo2();
   size_t Allocated = MI.uordblks;
@@ -404,7 +440,7 @@ static void callback(uintptr_t Base, UNUSED size_t Size, UNUSED void *Arg) {
 // To achieve this, we allocate a chunk for which the backing block will be
 // aligned on a page, then run the malloc_iterate on both the pages that the
 // block is a boundary for. It must only be seen once by the callback function.
-TEST(ScudoWrappersCTest, MallocIterateBoundary) {
+TEST_F(ScudoWrappersCTest, MallocIterateBoundary) {
   const size_t PageSize = static_cast<size_t>(sysconf(_SC_PAGESIZE));
 #if SCUDO_ANDROID
   // Android uses a 16 byte alignment for both 32 bit and 64 bit.
@@ -456,7 +492,7 @@ TEST(ScudoWrappersCTest, MallocIterateBoundary) {
 
 // Fuchsia doesn't have alarm, fork or malloc_info.
 #if !SCUDO_FUCHSIA
-TEST(ScudoWrappersCDeathTest, MallocDisableDeadlock) {
+TEST_F(ScudoWrappersCDeathTest, MallocDisableDeadlock) {
   // We expect heap operations within a disable/enable scope to deadlock.
   EXPECT_DEATH(
       {
@@ -471,7 +507,7 @@ TEST(ScudoWrappersCDeathTest, MallocDisableDeadlock) {
       "");
 }
 
-TEST(ScudoWrappersCTest, MallocInfo) {
+TEST_F(ScudoWrappersCTest, MallocInfo) {
   // Use volatile so that the allocations don't get optimized away.
   void *volatile P1 = malloc(1234);
   void *volatile P2 = malloc(4321);
@@ -491,7 +527,7 @@ TEST(ScudoWrappersCTest, MallocInfo) {
   free(P2);
 }
 
-TEST(ScudoWrappersCDeathTest, Fork) {
+TEST_F(ScudoWrappersCDeathTest, Fork) {
   void *P;
   pid_t Pid = fork();
   EXPECT_GE(Pid, 0) << strerror(errno);
@@ -543,7 +579,7 @@ static void *enableMalloc(UNUSED void *Unused) {
   return nullptr;
 }
 
-TEST(ScudoWrappersCTest, DisableForkEnable) {
+TEST_F(ScudoWrappersCTest, DisableForkEnable) {
   pthread_t ThreadId;
   Ready = false;
   EXPECT_EQ(pthread_create(&ThreadId, nullptr, &enableMalloc, nullptr), 0);

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 654bf547317809..c802ed22fbad00 100644
--- a/compiler-rt/lib/scudo/standalone/tests/wrappers_cpp_test.cpp
+++ b/compiler-rt/lib/scudo/standalone/tests/wrappers_cpp_test.cpp
@@ -24,6 +24,18 @@
 #define SKIP_MISMATCH_TESTS 0
 #endif
 
+void operator delete(void *, size_t) noexcept;
+void operator delete[](void *, size_t) noexcept;
+
+extern "C" {
+#ifndef SCUDO_ENABLE_HOOKS_TESTS
+#define SCUDO_ENABLE_HOOKS_TESTS 0
+#endif
+
+#if (SCUDO_ENABLE_HOOKS_TESTS == 1) && (SCUDO_ENABLE_HOOKS == 0)
+#error "Hooks tests should have hooks enabled as well!"
+#endif
+
 struct AllocContext {
   void *Ptr;
   size_t Size;
@@ -34,10 +46,7 @@ struct DeallocContext {
 static AllocContext AC;
 static DeallocContext DC;
 
-void operator delete(void *, size_t) noexcept;
-void operator delete[](void *, size_t) noexcept;
-
-extern "C" {
+#if (SCUDO_ENABLE_HOOKS_TESTS == 1)
 __attribute__((visibility("default"))) void __scudo_allocate_hook(void *Ptr,
                                                                   size_t Size) {
   AC.Ptr = Ptr;
@@ -46,60 +55,81 @@ __attribute__((visibility("default"))) void __scudo_allocate_hook(void *Ptr,
 __attribute__((visibility("default"))) void __scudo_deallocate_hook(void *Ptr) {
   DC.Ptr = Ptr;
 }
+#endif // (SCUDO_ENABLE_HOOKS_TESTS == 1)
 }
-// 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 ScudoWrappersCppTest : public Test {
+protected:
+  void SetUp() override {
+    if (SCUDO_ENABLE_HOOKS && !SCUDO_ENABLE_HOOKS_TESTS)
+      printf("Hooks are enabled but hooks tests are disabled.\n");
+  }
+
+  void verifyAllocHookPtr(UNUSED void *Ptr) {
+    if (SCUDO_ENABLE_HOOKS_TESTS)
+      EXPECT_EQ(Ptr, AC.Ptr);
+  }
+  void verifyAllocHookSize(UNUSED size_t Size) {
+    if (SCUDO_ENABLE_HOOKS_TESTS)
+      EXPECT_EQ(Size, AC.Size);
+  }
+  void verifyDeallocHookPtr(UNUSED void *Ptr) {
+    if (SCUDO_ENABLE_HOOKS_TESTS)
+      EXPECT_EQ(Ptr, DC.Ptr);
+  }
+
+  template <typename T> void testCxxNew() {
+    T *P = new T;
+    EXPECT_NE(P, nullptr);
+    verifyAllocHookPtr(P);
+    verifyAllocHookSize(sizeof(T));
+    memset(P, 0x42, sizeof(T));
+    EXPECT_DEATH(delete[] P, "");
+    delete P;
+    verifyDeallocHookPtr(P);
+    EXPECT_DEATH(delete P, "");
+
+    P = new T;
+    EXPECT_NE(P, nullptr);
+    memset(P, 0x42, sizeof(T));
+    operator delete(P, sizeof(T));
+    verifyDeallocHookPtr(P);
+
+    P = new (std::nothrow) T;
+    verifyAllocHookPtr(P);
+    verifyAllocHookSize(sizeof(T));
+    EXPECT_NE(P, nullptr);
+    memset(P, 0x42, sizeof(T));
+    delete P;
+    verifyDeallocHookPtr(P);
+
+    const size_t N = 16U;
+    T *A = new T[N];
+    EXPECT_NE(A, nullptr);
+    verifyAllocHookPtr(A);
+    verifyAllocHookSize(sizeof(T) * N);
+    memset(A, 0x42, sizeof(T) * N);
+    EXPECT_DEATH(delete A, "");
+    delete[] A;
+    verifyDeallocHookPtr(A);
+    EXPECT_DEATH(delete[] A, "");
+
+    A = new T[N];
+    EXPECT_NE(A, nullptr);
+    memset(A, 0x42, sizeof(T) * N);
+    operator delete[](A, sizeof(T) * N);
+    verifyDeallocHookPtr(A);
+
+    A = new (std::nothrow) T[N];
+    verifyAllocHookPtr(A);
+    verifyAllocHookSize(sizeof(T) * N);
+    EXPECT_NE(A, nullptr);
+    memset(A, 0x42, sizeof(T) * N);
+    delete[] A;
+    verifyDeallocHookPtr(A);
+  }
+};
+using ScudoWrappersCppDeathTest = ScudoWrappersCppTest;
 
 class Pixel {
 public:
@@ -109,7 +139,10 @@ class Pixel {
   Color C = Color::Red;
 };
 
-TEST(ScudoWrappersCppDeathTest, New) {
+// 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.
+
+TEST_F(ScudoWrappersCppDeathTest, New) {
   if (getenv("SKIP_TYPE_MISMATCH") || SKIP_MISMATCH_TESTS) {
     printf("Skipped type mismatch tests.\n");
     return;
@@ -150,7 +183,7 @@ static void stressNew() {
   }
 }
 
-TEST(ScudoWrappersCppTest, ThreadedNew) {
+TEST_F(ScudoWrappersCppTest, ThreadedNew) {
   // TODO: Investigate why libc sometimes crashes with tag missmatch in
   // __pthread_clockjoin_ex.
   std::unique_ptr<scudo::ScopedDisableMemoryTagChecks> NoTags;
@@ -172,7 +205,7 @@ TEST(ScudoWrappersCppTest, ThreadedNew) {
 }
 
 #if !SCUDO_FUCHSIA
-TEST(ScudoWrappersCppTest, AllocAfterFork) {
+TEST_F(ScudoWrappersCppTest, AllocAfterFork) {
   // This test can fail flakily when ran as a part of large number of
   // other tests if the maxmimum number of mappings allowed is low.
   // We tried to reduce the number of iterations of the loops with

diff  --git a/compiler-rt/lib/scudo/standalone/wrappers_c.cpp b/compiler-rt/lib/scudo/standalone/wrappers_c.cpp
index 0b204271c81ce7..60014a0f66bf54 100644
--- a/compiler-rt/lib/scudo/standalone/wrappers_c.cpp
+++ b/compiler-rt/lib/scudo/standalone/wrappers_c.cpp
@@ -12,6 +12,8 @@
 #if !SCUDO_ANDROID || !_BIONIC
 
 #include "allocator_config.h"
+#include "internal_defs.h"
+#include "platform.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 0bd5eddfa0b1c1..e213da73393b5d 100644
--- a/compiler-rt/lib/scudo/standalone/wrappers_c.inc
+++ b/compiler-rt/lib/scudo/standalone/wrappers_c.inc
@@ -18,13 +18,14 @@
 #endif
 
 static void reportAllocation(void *ptr, size_t size) {
-  if (__scudo_allocate_hook && ptr)
-    __scudo_allocate_hook(ptr, size);
+  if (SCUDO_ENABLE_HOOKS)
+    if (__scudo_allocate_hook && ptr)
+      __scudo_allocate_hook(ptr, size);
 }
-
 static void reportDeallocation(void *ptr) {
-  if (__scudo_deallocate_hook)
-    __scudo_deallocate_hook(ptr);
+  if (SCUDO_ENABLE_HOOKS)
+    if (__scudo_deallocate_hook)
+      __scudo_deallocate_hook(ptr);
 }
 
 extern "C" {

diff  --git a/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp b/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
index db824e6f754737..4e8e37ac293b86 100644
--- a/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
+++ b/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
@@ -12,6 +12,8 @@
 #if SCUDO_ANDROID && _BIONIC
 
 #include "allocator_config.h"
+#include "internal_defs.h"
+#include "platform.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 9ea2aaed1e7857..098d4f71acc4af 100644
--- a/compiler-rt/lib/scudo/standalone/wrappers_cpp.cpp
+++ b/compiler-rt/lib/scudo/standalone/wrappers_cpp.cpp
@@ -12,6 +12,8 @@
 #if !SCUDO_ANDROID || !_BIONIC
 
 #include "allocator_config.h"
+#include "internal_defs.h"
+#include "platform.h"
 #include "scudo/interface.h"
 #include "wrappers_c.h"
 
@@ -23,13 +25,14 @@ 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);
+  if (SCUDO_ENABLE_HOOKS)
+    if (__scudo_allocate_hook && ptr)
+      __scudo_allocate_hook(ptr, size);
 }
-
 static void reportDeallocation(void *ptr) {
-  if (__scudo_deallocate_hook)
-    __scudo_deallocate_hook(ptr);
+  if (SCUDO_ENABLE_HOOKS)
+    if (__scudo_deallocate_hook)
+      __scudo_deallocate_hook(ptr);
 }
 
 INTERFACE WEAK void *operator new(size_t size) {


        


More information about the llvm-commits mailing list