mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-24 06:10:12 +00:00
[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:
parent
91b3ca3966
commit
4f76810d48
@ -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;
|
||||
|
@ -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})
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user