From 4f76810d4860d851f069aa0caca24c54ab698c3b Mon Sep 17 00:00:00 2001 From: Chia-hung Duan Date: Thu, 24 Aug 2023 17:52:35 +0000 Subject: [PATCH] [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 --- compiler-rt/lib/scudo/standalone/combined.h | 10 -- .../lib/scudo/standalone/tests/CMakeLists.txt | 8 -- .../standalone/tests/scudo_hooks_test.cpp | 114 ------------------ .../standalone/tests/wrappers_c_test.cpp | 64 +++++++++- .../standalone/tests/wrappers_cpp_test.cpp | 34 ++++++ .../lib/scudo/standalone/wrappers_c.cpp | 1 + .../lib/scudo/standalone/wrappers_c.inc | 73 ++++++++--- .../scudo/standalone/wrappers_c_bionic.cpp | 1 + .../lib/scudo/standalone/wrappers_cpp.cpp | 63 ++++++++-- 9 files changed, 206 insertions(+), 162 deletions(-) delete mode 100644 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 e1db7a703011..8cc84adcd484 100644 --- a/compiler-rt/lib/scudo/standalone/combined.h +++ b/compiler-rt/lib/scudo/standalone/combined.h @@ -329,8 +329,6 @@ public: #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 @@ public: Chunk::SizeOrUnusedBytesMask; Chunk::storeHeader(Cookie, Ptr, &Header); - if (UNLIKELY(&__scudo_allocate_hook)) - __scudo_allocate_hook(TaggedPtr, Size); - return TaggedPtr; } @@ -551,9 +546,6 @@ public: // 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 @@ public: 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 cbb85ce3ec2e..71ad3830c88c 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 7184ec12a8bb..000000000000 --- 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 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 c921da980cad..d0cc0fa3c650 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(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(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(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(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(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(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(P))[I]); + if (OldP == P) { + EXPECT_EQ(AC.Ptr, reinterpret_cast(0xdeadbeef)); + } else { + EXPECT_EQ(P, AC.Ptr); + EXPECT_EQ(Size * 2U, AC.Size); + EXPECT_EQ(OldP, DC.Ptr); + } + AC.Ptr = reinterpret_cast(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(P))[I]); + if (OldP == P) { + EXPECT_EQ(AC.Ptr, reinterpret_cast(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(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 987e4099aa77..654bf5473178 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 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 b4d51be716cc..0b204271c81c 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 a475927b9f51..0bd5eddfa0b1 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 1b9fe67d920c..db824e6f7547 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 374e36d72b3d..9ea2aaed1e78 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 @@ -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(align)); + void *Ptr = Allocator.allocate(size, scudo::Chunk::Origin::New, + static_cast(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(align)); + void *Ptr = Allocator.allocate(size, scudo::Chunk::Origin::NewArray, + static_cast(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(align)); + void *Ptr = Allocator.allocate(size, scudo::Chunk::Origin::New, + static_cast(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(align)); + void *Ptr = Allocator.allocate(size, scudo::Chunk::Origin::NewArray, + static_cast(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(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(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(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(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(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(align)); }