[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
This commit is contained in:
Chia-hung Duan 2023-08-24 17:52:35 +00:00
parent 91b3ca3966
commit 4f76810d48
9 changed files with 206 additions and 162 deletions

View File

@ -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;

View File

@ -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})

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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 {

View File

@ -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"

View File

@ -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) {

View File

@ -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"

View File

@ -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));
}