re-implement glibc-malloc hooking
This commit is contained in:
parent
e1b903be06
commit
467919e950
3
deps/oblib/src/lib/CMakeLists.txt
vendored
3
deps/oblib/src/lib/CMakeLists.txt
vendored
@ -411,7 +411,8 @@ target_link_libraries(ob_malloc ob_malloc_object)
|
||||
|
||||
add_library(malloc_hook STATIC
|
||||
alloc/malloc_hook.cpp
|
||||
alloc/malloc_hook.h)
|
||||
alloc/malloc_hook.h
|
||||
alloc/malloc_hook_extended.cpp)
|
||||
target_link_libraries(malloc_hook oblib_base)
|
||||
|
||||
if(OB_BUILD_CLOSE_MODULES)
|
||||
|
149
deps/oblib/src/lib/alloc/malloc_hook.cpp
vendored
149
deps/oblib/src/lib/alloc/malloc_hook.cpp
vendored
@ -11,12 +11,16 @@
|
||||
*/
|
||||
|
||||
#include "malloc_hook.h"
|
||||
#include <dlfcn.h>
|
||||
#include "lib/utility/utility.h"
|
||||
#include "lib/utility/ob_defer.h"
|
||||
#include "lib/allocator/ob_mem_leak_checker.h"
|
||||
#include "lib/allocator/ob_malloc.h"
|
||||
|
||||
#define OBMALLOC_ATTR(s) __attribute__((s))
|
||||
#define OBMALLOC_EXPORT __attribute__((visibility("default")))
|
||||
#define OBMALLOC_ALLOC_SIZE(s) __attribute__((alloc_size(s)))
|
||||
#define OBMALLOC_NOTHROW __attribute__((nothrow))
|
||||
#define LIBC_ALIAS(fn) __attribute__((alias (#fn), used))
|
||||
|
||||
using namespace oceanbase;
|
||||
using namespace oceanbase::common;
|
||||
using namespace oceanbase::lib;
|
||||
@ -37,7 +41,7 @@ struct Header
|
||||
{
|
||||
static const uint32_t MAGIC_CODE = 0XA1B2C3D1;
|
||||
static const uint32_t SIZE;
|
||||
Header(int32_t size, bool from_mmap)
|
||||
Header(uint32_t size, bool from_mmap)
|
||||
: magic_code_(MAGIC_CODE),
|
||||
data_size_(size),
|
||||
offset_(0),
|
||||
@ -47,7 +51,7 @@ struct Header
|
||||
void mark_unused() { magic_code_ &= ~0x1; }
|
||||
static Header *ptr2header(void *ptr) { return reinterpret_cast<Header*>((char*)ptr - SIZE); }
|
||||
uint32_t magic_code_;
|
||||
int32_t data_size_;
|
||||
uint32_t data_size_;
|
||||
uint32_t offset_;
|
||||
uint8_t from_mmap_;
|
||||
char padding_[3];
|
||||
@ -55,7 +59,6 @@ struct Header
|
||||
} __attribute__((aligned (16)));
|
||||
|
||||
const uint32_t Header::SIZE = offsetof(Header, data_);
|
||||
const size_t max_retry_size = 2 << 30; // 2G
|
||||
|
||||
void *ob_malloc_retry(size_t size)
|
||||
{
|
||||
@ -72,7 +75,7 @@ void *ob_malloc_retry(size_t size)
|
||||
if (OB_ISNULL(ptr)) {
|
||||
::usleep(10000); // 10ms
|
||||
}
|
||||
} while (OB_ISNULL(ptr) && !(size > max_retry_size || 0 == size));
|
||||
} while (OB_ISNULL(ptr) && 0 != size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@ -95,9 +98,15 @@ static inline int ob_munmap(void *addr, size_t length)
|
||||
return syscall(SYS_munmap, addr, length);
|
||||
}
|
||||
|
||||
void *ob_malloc_hook(size_t size, const void *)
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
OBMALLOC_EXPORT
|
||||
void OBMALLOC_NOTHROW *
|
||||
OBMALLOC_ATTR(malloc) OBMALLOC_ALLOC_SIZE(1)
|
||||
malloc(size_t size)
|
||||
{
|
||||
void *ptr = nullptr;
|
||||
abort_unless(size <= UINT32_MAX - Header::SIZE);
|
||||
size_t real_size = size + Header::SIZE;
|
||||
void *tmp_ptr = nullptr;
|
||||
bool from_mmap = false;
|
||||
@ -113,17 +122,17 @@ void *ob_malloc_hook(size_t size, const void *)
|
||||
tmp_ptr = ob_malloc_retry(real_size);
|
||||
}
|
||||
if (OB_LIKELY(tmp_ptr != nullptr)) {
|
||||
abort_unless(size <= INT32_MAX);
|
||||
auto *header = new (tmp_ptr) Header((int32_t)size, from_mmap);
|
||||
Header *header = new (tmp_ptr) Header((uint32_t)size, from_mmap);
|
||||
ptr = header->data_;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void ob_free_hook(void *ptr, const void *)
|
||||
OBMALLOC_EXPORT void OBMALLOC_NOTHROW
|
||||
free(void *ptr)
|
||||
{
|
||||
if (OB_LIKELY(ptr != nullptr)) {
|
||||
auto *header = Header::ptr2header(ptr);
|
||||
Header *header = Header::ptr2header(ptr);
|
||||
abort_unless(header->check_magic_code());
|
||||
header->mark_unused();
|
||||
void *orig_ptr = (char*)header - header->offset_;
|
||||
@ -138,9 +147,17 @@ void ob_free_hook(void *ptr, const void *)
|
||||
}
|
||||
}
|
||||
|
||||
void *ob_realloc_hook(void *ptr, size_t size, const void *caller)
|
||||
OBMALLOC_EXPORT
|
||||
void OBMALLOC_NOTHROW *
|
||||
OBMALLOC_ALLOC_SIZE(2)
|
||||
realloc(void *ptr, size_t size)
|
||||
{
|
||||
if (0 == size && nullptr != ptr) {
|
||||
free(ptr);
|
||||
return nullptr;
|
||||
}
|
||||
void *nptr = nullptr;
|
||||
abort_unless(size <= UINT32_MAX - Header::SIZE);
|
||||
size_t real_size = size + Header::SIZE;
|
||||
void *tmp_ptr = nullptr;
|
||||
bool from_mmap = false;
|
||||
@ -156,60 +173,60 @@ void *ob_realloc_hook(void *ptr, size_t size, const void *caller)
|
||||
tmp_ptr = ob_malloc_retry(real_size);
|
||||
}
|
||||
if (OB_LIKELY(tmp_ptr != nullptr)) {
|
||||
abort_unless(size <= INT32_MAX);
|
||||
auto *header = new (tmp_ptr) Header((int32_t)size, from_mmap);
|
||||
Header *header = new (tmp_ptr) Header((uint32_t)size, from_mmap);
|
||||
nptr = header->data_;
|
||||
if (ptr != nullptr) {
|
||||
auto *old_header = Header::ptr2header(ptr);
|
||||
Header *old_header = Header::ptr2header(ptr);
|
||||
abort_unless(old_header->check_magic_code());
|
||||
memmove(nptr, ptr, MIN(old_header->data_size_, size));
|
||||
ob_free_hook(old_header->data_, caller);
|
||||
free(old_header->data_);
|
||||
}
|
||||
}
|
||||
return nptr;
|
||||
}
|
||||
|
||||
void *ob_memalign_hook(size_t alignment, size_t size, const void *)
|
||||
OBMALLOC_EXPORT
|
||||
void OBMALLOC_NOTHROW *
|
||||
OBMALLOC_ATTR(malloc)
|
||||
memalign(size_t alignment, size_t size)
|
||||
{
|
||||
void *ptr = nullptr;
|
||||
if (OB_LIKELY(size > 0)) {
|
||||
// Make sure alignment is power of 2
|
||||
{
|
||||
size_t a = 8;
|
||||
while (a < alignment)
|
||||
a <<= 1;
|
||||
alignment = a;
|
||||
}
|
||||
size_t real_size = 2 * MAX(alignment, Header::SIZE) + size;
|
||||
void *tmp_ptr = nullptr;
|
||||
bool from_mmap = false;
|
||||
if (OB_UNLIKELY(!g_malloc_hook_inited || in_hook())) {
|
||||
if (MAP_FAILED == (tmp_ptr = ob_mmap(nullptr, real_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0))) {
|
||||
tmp_ptr = nullptr;
|
||||
}
|
||||
from_mmap = true;
|
||||
} else {
|
||||
bool in_hook_bak = in_hook();
|
||||
in_hook()= true;
|
||||
DEFER(in_hook()= in_hook_bak);
|
||||
tmp_ptr = ob_malloc_retry(real_size);
|
||||
}
|
||||
if (OB_LIKELY(tmp_ptr != nullptr)) {
|
||||
char *start = (char *)tmp_ptr + Header::SIZE;
|
||||
char *align_ptr = (char *)up_align(reinterpret_cast<int64_t>(start), alignment);
|
||||
char *pheader = align_ptr - Header::SIZE;
|
||||
size_t offset = pheader - (char*)tmp_ptr;
|
||||
abort_unless(size <= INT32_MAX);
|
||||
auto *header = new (pheader) Header((int32_t)size, from_mmap);
|
||||
header->offset_ = (uint32_t)offset;
|
||||
ptr = header->data_;
|
||||
// avoid alignment overflow
|
||||
abort_unless(alignment <= UINT32_MAX / 2);
|
||||
// Make sure alignment is power of 2
|
||||
{
|
||||
size_t a = 8;
|
||||
while (a < alignment)
|
||||
a <<= 1;
|
||||
alignment = a;
|
||||
}
|
||||
abort_unless(size <= UINT32_MAX - 2 * MAX(alignment, Header::SIZE));
|
||||
size_t real_size = 2 * MAX(alignment, Header::SIZE) + size;
|
||||
void *tmp_ptr = nullptr;
|
||||
bool from_mmap = false;
|
||||
if (OB_UNLIKELY(!g_malloc_hook_inited || in_hook())) {
|
||||
if (MAP_FAILED == (tmp_ptr = ob_mmap(nullptr, real_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0))) {
|
||||
tmp_ptr = nullptr;
|
||||
}
|
||||
from_mmap = true;
|
||||
} else {
|
||||
bool in_hook_bak = in_hook();
|
||||
in_hook()= true;
|
||||
DEFER(in_hook()= in_hook_bak);
|
||||
tmp_ptr = ob_malloc_retry(real_size);
|
||||
}
|
||||
if (OB_LIKELY(tmp_ptr != nullptr)) {
|
||||
char *start = (char *)tmp_ptr + Header::SIZE;
|
||||
char *align_ptr = (char *)up_align(reinterpret_cast<int64_t>(start), alignment);
|
||||
char *pheader = align_ptr - Header::SIZE;
|
||||
size_t offset = pheader - (char*)tmp_ptr;
|
||||
Header *header = new (pheader) Header((uint32_t)size, from_mmap);
|
||||
header->offset_ = (uint32_t)offset;
|
||||
ptr = header->data_;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
void *ob_mmap_hook(void *addr, size_t length, int prot, int flags, int fd, loff_t offset)
|
||||
{
|
||||
return ob_mmap(addr, length, prot, flags, fd, offset);
|
||||
@ -220,39 +237,25 @@ int ob_munmap_hook(void *addr, size_t length)
|
||||
return ob_munmap(addr, length);
|
||||
}
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#if !defined(__MALLOC_HOOK_VOLATILE)
|
||||
#define MALLOC_HOOK_MAYBE_VOLATILE /**/
|
||||
#else
|
||||
#define MALLOC_HOOK_MAYBE_VOLATILE __MALLOC_HOOK_VOLATILE
|
||||
#endif
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
__attribute__((visibility("default"))) void *(*MALLOC_HOOK_MAYBE_VOLATILE __malloc_hook)(size_t, const void *) = ob_malloc_hook;
|
||||
__attribute__((visibility("default"))) void (*MALLOC_HOOK_MAYBE_VOLATILE __free_hook)(void *, const void *) = ob_free_hook;
|
||||
__attribute__((visibility("default"))) void *(*MALLOC_HOOK_MAYBE_VOLATILE __realloc_hook)(void *, size_t, const void *) = ob_realloc_hook;
|
||||
__attribute__((visibility("default"))) void *(*MALLOC_HOOK_MAYBE_VOLATILE __memalign_hook)(size_t, size_t, const void *) = ob_memalign_hook;
|
||||
|
||||
__attribute__((visibility("default"))) void *mmap(void *addr, size_t, int, int, int, loff_t) __attribute__((weak,alias("ob_mmap_hook")));
|
||||
__attribute__((visibility("default"))) void *mmap64(void *addr, size_t, int, int, int, loff_t) __attribute__((weak,alias("ob_mmap_hook")));
|
||||
__attribute__((visibility("default"))) int munmap(void *addr, size_t length) __attribute__((weak,alias("ob_munmap_hook")));
|
||||
|
||||
size_t malloc_usable_size(void *ptr)
|
||||
OBMALLOC_EXPORT size_t OBMALLOC_NOTHROW
|
||||
malloc_usable_size(void *ptr)
|
||||
{
|
||||
size_t ret = 0;
|
||||
static const bool malloc_hook_disabled = glibc_prereq(2, 34);
|
||||
if (malloc_hook_disabled) {
|
||||
static int (*real_malloc_usable_size)(void *ptr) =
|
||||
(typeof(real_malloc_usable_size))dlsym(RTLD_NEXT, "malloc_usable_size");
|
||||
ret = real_malloc_usable_size(ptr);
|
||||
} else if (OB_LIKELY(ptr != nullptr)) {
|
||||
auto *header = Header::ptr2header(ptr);
|
||||
if (OB_LIKELY(nullptr != ptr)) {
|
||||
Header *header = Header::ptr2header(ptr);
|
||||
abort_unless(header->check_magic_code());
|
||||
ret = header->data_size_;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *__libc_malloc(size_t size) LIBC_ALIAS(malloc);
|
||||
void *__libc_realloc(void* ptr, size_t size) LIBC_ALIAS(realloc);
|
||||
void __libc_free(void* ptr) LIBC_ALIAS(free);
|
||||
void *__libc_memalign(size_t align, size_t s) LIBC_ALIAS(memalign);
|
||||
|
||||
EXTERN_C_END
|
||||
|
280
deps/oblib/src/lib/alloc/malloc_hook_extended.cpp
vendored
Normal file
280
deps/oblib/src/lib/alloc/malloc_hook_extended.cpp
vendored
Normal file
@ -0,0 +1,280 @@
|
||||
/**
|
||||
* Copyright (c) 2024 OceanBase
|
||||
* OceanBase CE is licensed under Mulan PubL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
||||
* You may obtain a copy of Mulan PubL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPubL-2.0
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PubL v2 for more details.
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <new>
|
||||
#include <cerrno>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <gnu/libc-version.h>
|
||||
|
||||
#define LIKELY(x) __builtin_expect(!!(x),!!1)
|
||||
#define UNLIKELY(x) __builtin_expect(!!(x),!!0)
|
||||
#define MALLOC_ATTR(s) __attribute__((s))
|
||||
#define MALLOC_EXPORT __attribute__((visibility("default")))
|
||||
#define MALLOC_ALLOC_SIZE(s) __attribute__((alloc_size(s)))
|
||||
#define MALLOC_ALLOC_SIZE2(s1, s2) __attribute__((alloc_size(s1, s2)))
|
||||
#define MALLOC_NOTHROW __attribute__((nothrow))
|
||||
#define powerof2(x) ((((x) - 1) & (x)) == 0)
|
||||
#define LIBC_ALIAS(fn) __attribute__((alias (#fn), used))
|
||||
|
||||
static size_t get_page_size()
|
||||
{
|
||||
static size_t ps = getpagesize();
|
||||
return ps;
|
||||
}
|
||||
|
||||
void get_glibc_version(int &major, int &minor)
|
||||
{
|
||||
major = 0;
|
||||
minor = 0;
|
||||
const char *glibc_version = gnu_get_libc_version();
|
||||
if (NULL != glibc_version) {
|
||||
sscanf(glibc_version, "%d.%d", &major, &minor);
|
||||
}
|
||||
}
|
||||
|
||||
bool glibc_prereq(int major, int minor)
|
||||
{
|
||||
int cur_major = 0;
|
||||
int cur_minor = 0;
|
||||
get_glibc_version(cur_major, cur_minor);
|
||||
return (cur_major > major) || (cur_major == major && cur_minor >= minor);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern void *malloc(size_t size);
|
||||
extern void free(void *ptr);
|
||||
extern void *realloc(void *ptr, size_t size);
|
||||
extern void *memalign(size_t alignment, size_t size);
|
||||
|
||||
MALLOC_EXPORT
|
||||
void MALLOC_NOTHROW *
|
||||
MALLOC_ATTR(malloc) MALLOC_ALLOC_SIZE2(1, 2)
|
||||
calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
size_t real_size;
|
||||
if (UNLIKELY(__builtin_mul_overflow(nmemb, size, &real_size))) {
|
||||
abort();
|
||||
}
|
||||
void *ptr = malloc(real_size);
|
||||
if (LIKELY(nullptr != ptr && real_size > 0)) {
|
||||
memset(ptr, 0, real_size);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
MALLOC_EXPORT void MALLOC_NOTHROW
|
||||
cfree(void* ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
MALLOC_EXPORT void MALLOC_NOTHROW
|
||||
free_sized(void* ptr, size_t size)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
MALLOC_EXPORT void MALLOC_NOTHROW
|
||||
free_aligned_sized(void* ptr, size_t alignment, size_t size)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
MALLOC_EXPORT
|
||||
void MALLOC_NOTHROW *
|
||||
MALLOC_ATTR(malloc) MALLOC_ALLOC_SIZE(2)
|
||||
aligned_alloc(size_t alignment, size_t size)
|
||||
{
|
||||
// glibc-2.38 and above adopt ISO 17 standard aligned_alloc
|
||||
static const bool newstd = glibc_prereq(2, 38);
|
||||
if (newstd) {
|
||||
if (!powerof2 (alignment) || alignment == 0) {
|
||||
errno = EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return memalign(alignment, size);
|
||||
}
|
||||
|
||||
MALLOC_EXPORT int MALLOC_NOTHROW
|
||||
MALLOC_ATTR(nonnull(1))
|
||||
posix_memalign(void** memptr, size_t alignment, size_t size)
|
||||
{
|
||||
int err = 0;
|
||||
if (0 != alignment % sizeof (void *)
|
||||
|| 0 != !powerof2 (alignment / sizeof (void *))
|
||||
|| 0 == alignment
|
||||
|| nullptr == memptr) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
*memptr = nullptr;
|
||||
void *ptr = memalign(alignment, size);
|
||||
if (nullptr == ptr) {
|
||||
err = ENOMEM;
|
||||
} else {
|
||||
*memptr = ptr;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
MALLOC_EXPORT
|
||||
void MALLOC_NOTHROW *
|
||||
MALLOC_ATTR(malloc)
|
||||
valloc(size_t size)
|
||||
{
|
||||
return memalign(get_page_size(), size);
|
||||
}
|
||||
|
||||
MALLOC_EXPORT
|
||||
void MALLOC_NOTHROW *
|
||||
MALLOC_ATTR(malloc)
|
||||
pvalloc(size_t size)
|
||||
{
|
||||
const size_t pagesize = get_page_size();
|
||||
size_t page_mask = pagesize - 1;
|
||||
size_t rounded_bytes;
|
||||
if (UNLIKELY(__builtin_add_overflow(size, page_mask, &rounded_bytes))) {
|
||||
abort();
|
||||
}
|
||||
rounded_bytes = rounded_bytes & ~(page_mask);
|
||||
return memalign(pagesize, rounded_bytes);
|
||||
}
|
||||
|
||||
void *__libc_calloc(size_t n, size_t size) LIBC_ALIAS(calloc);
|
||||
void __libc_free_sized(void* ptr, size_t size) LIBC_ALIAS(free_sized);
|
||||
void __libc_free_aligned_sized(void* ptr, size_t alignment, size_t size) LIBC_ALIAS(free_aligned_sized);
|
||||
void *__libc_valloc(size_t size) LIBC_ALIAS(valloc);
|
||||
void *__libc_pvalloc(size_t size) LIBC_ALIAS(pvalloc);
|
||||
int __posix_memalign(void** r, size_t a, size_t s) LIBC_ALIAS(posix_memalign);
|
||||
|
||||
} // extern "C" end
|
||||
|
||||
void *operator new(std::size_t size)
|
||||
{
|
||||
void *ptr = malloc(size);
|
||||
if (UNLIKELY(nullptr == ptr)) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *operator new[](std::size_t size)
|
||||
{
|
||||
void *ptr = malloc(size);
|
||||
if (UNLIKELY(nullptr == ptr)) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *operator new(std::size_t size, const std::nothrow_t &) noexcept {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *operator new[](std::size_t size, const std::nothrow_t &) noexcept {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void operator delete(void *ptr) noexcept
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void *ptr) noexcept
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete(void *ptr, const std::nothrow_t &) noexcept
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void *ptr, const std::nothrow_t &) noexcept
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
#if __cpp_sized_deallocation >= 201309
|
||||
// C++14 sized-delete operators
|
||||
void operator delete(void *ptr, std::size_t size) noexcept
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void *ptr, std::size_t size) noexcept
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __cpp_aligned_new >= 201606
|
||||
// C++17 aligned operators
|
||||
void *operator new(std::size_t size, std::align_val_t alignment) {
|
||||
void *ptr = memalign(static_cast<std::size_t>(alignment), size);
|
||||
if (UNLIKELY(nullptr == ptr)) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *operator new[](std::size_t size, std::align_val_t alignment) {
|
||||
void *ptr = memalign(static_cast<std::size_t>(alignment), size);
|
||||
if (UNLIKELY(nullptr == ptr)) {
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t &) noexcept {
|
||||
return memalign(static_cast<std::size_t>(alignment), size);
|
||||
}
|
||||
|
||||
void *operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t &) noexcept {
|
||||
return memalign(static_cast<std::size_t>(alignment), size);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr, std::align_val_t) noexcept
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr, std::align_val_t, const std::nothrow_t &) noexcept
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr, std::size_t size, std::align_val_t al) noexcept
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr, std::align_val_t) noexcept
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr, std::align_val_t, const std::nothrow_t &) noexcept
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr, std::size_t size, std::align_val_t al) noexcept
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
4
deps/oblib/unittest/CMakeLists.txt
vendored
4
deps/oblib/unittest/CMakeLists.txt
vendored
@ -6,9 +6,9 @@ enable_testing()
|
||||
|
||||
function(oblib_addtest mainfile)
|
||||
get_filename_component(testname ${mainfile} NAME_WE)
|
||||
add_executable(${testname} ${ARGV})
|
||||
add_executable(${testname} ${mainfile})
|
||||
add_test(${testname} ${testname})
|
||||
target_link_libraries(${testname} PRIVATE oblib oblib_testbase -static-libgcc -static-libstdc++
|
||||
target_link_libraries(${testname} PRIVATE oblib oblib_testbase -static-libgcc -static-libstdc++ ${ARGN}
|
||||
${OB_RELRO_FLAG} -Wl,-T,${CMAKE_SOURCE_DIR}/rpm/ld.lds)
|
||||
endfunction()
|
||||
|
||||
|
2
deps/oblib/unittest/lib/CMakeLists.txt
vendored
2
deps/oblib/unittest/lib/CMakeLists.txt
vendored
@ -10,7 +10,7 @@ oblib_addtest(parquet/test_parquet.cpp)
|
||||
oblib_addtest(alloc/test_alloc_struct.cpp)
|
||||
oblib_addtest(alloc/test_block_set.cpp)
|
||||
oblib_addtest(alloc/test_chunk_mgr.cpp)
|
||||
oblib_addtest(alloc/test_malloc_hook.cpp)
|
||||
oblib_addtest(alloc/test_malloc_hook.cpp malloc_hook)
|
||||
oblib_addtest(alloc/test_malloc_allocator.cpp)
|
||||
oblib_addtest(alloc/test_malloc_allocator_new.cpp)
|
||||
oblib_addtest(alloc/test_object_mgr.cpp)
|
||||
|
299
deps/oblib/unittest/lib/alloc/test_malloc_hook.cpp
vendored
299
deps/oblib/unittest/lib/alloc/test_malloc_hook.cpp
vendored
@ -21,6 +21,7 @@ using namespace oceanbase::common;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
init_malloc_hook();
|
||||
oceanbase::common::ObLogger::get_logger().set_log_level("INFO");
|
||||
OB_LOGGER.set_log_level("INFO");
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
@ -40,141 +41,199 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct Header
|
||||
{
|
||||
static const uint32_t MAGIC_CODE = 0XA1B2C3D1;
|
||||
static const uint32_t SIZE;
|
||||
Header(int32_t size, bool from_mmap)
|
||||
: magic_code_(MAGIC_CODE),
|
||||
data_size_(size),
|
||||
offset_(0),
|
||||
from_mmap_(from_mmap)
|
||||
{}
|
||||
bool check_magic_code() const { return MAGIC_CODE == magic_code_; }
|
||||
void mark_unused() { magic_code_ &= ~0x1; }
|
||||
static Header *ptr2header(void *ptr) { return reinterpret_cast<Header*>((char*)ptr - SIZE); }
|
||||
uint32_t magic_code_;
|
||||
int32_t data_size_;
|
||||
uint32_t offset_;
|
||||
uint8_t from_mmap_;
|
||||
char padding_[3];
|
||||
char data_[0];
|
||||
} __attribute__((aligned (16)));
|
||||
|
||||
#if 0
|
||||
TEST_F(TestMallocHook, Basic)
|
||||
{
|
||||
const static size_t size = 100;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (0 == i) {
|
||||
lib::glibc_hook_opt = GHO_NOHOOK;
|
||||
} else if (1 == i) {
|
||||
lib::glibc_hook_opt = GHO_HOOK;
|
||||
} else {
|
||||
lib::glibc_hook_opt = GHO_NONULL;
|
||||
}
|
||||
bool from_glibc = 0 == i;
|
||||
void *ptr = nullptr;
|
||||
void *ptr = nullptr;
|
||||
int ret = 0;
|
||||
|
||||
// calloc
|
||||
char zero_buf[100];
|
||||
memset(zero_buf, 0 , 100);
|
||||
ptr = calloc(10, 10);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
memset(ptr, 0, size);
|
||||
HookHeader *header = reinterpret_cast<HookHeader*>((char*)ptr - HOOK_HEADER_SIZE);
|
||||
ASSERT_TRUE(header->from_glibc_ == from_glibc);
|
||||
ASSERT_EQ(header->data_size_, 10 * 10);
|
||||
// check 0
|
||||
ASSERT_EQ(0, memcmp(ptr, zero_buf, 100));
|
||||
free(ptr);
|
||||
// calloc
|
||||
char zero_buf[100];
|
||||
memset(zero_buf, 0 , 100);
|
||||
ptr = calloc(10, 10);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
memset(ptr, 0, size);
|
||||
Header *header = Header::ptr2header(ptr);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
ASSERT_EQ(header->data_size_, 10 * 10);
|
||||
// check 0
|
||||
ASSERT_EQ(0, memcmp(ptr, zero_buf, 100));
|
||||
free(ptr);
|
||||
|
||||
// malloc
|
||||
ptr = malloc(size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
header = reinterpret_cast<HookHeader*>((char*)ptr - HOOK_HEADER_SIZE);
|
||||
ASSERT_TRUE(header->from_glibc_ == from_glibc);
|
||||
ASSERT_EQ(header->data_size_, size);
|
||||
char buf[size];
|
||||
memset(buf, 'a', size);
|
||||
memcpy(ptr, buf, size);
|
||||
// malloc
|
||||
ptr = malloc(size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
header = Header::ptr2header(ptr);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
ASSERT_EQ(header->data_size_, size);
|
||||
char buf[size];
|
||||
memset(buf, 'a', size);
|
||||
memcpy(ptr, buf, size);
|
||||
|
||||
// realloc
|
||||
void *new_ptr = realloc(ptr, size * 2);
|
||||
ASSERT_NE(new_ptr, nullptr);
|
||||
header = reinterpret_cast<HookHeader*>((char*)new_ptr - HOOK_HEADER_SIZE);
|
||||
ASSERT_TRUE(header->from_glibc_ == from_glibc);
|
||||
ASSERT_EQ(header->data_size_, size * 2);
|
||||
ASSERT_EQ(0, memcmp(new_ptr, buf, size));
|
||||
free(new_ptr);
|
||||
// realloc
|
||||
void *new_ptr = realloc(ptr, size * 2);
|
||||
ASSERT_NE(new_ptr, nullptr);
|
||||
header = Header::ptr2header(new_ptr);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
ASSERT_EQ(header->data_size_, size * 2);
|
||||
ASSERT_EQ(0, memcmp(new_ptr, buf, size));
|
||||
free(new_ptr);
|
||||
|
||||
// realloc(nullptr, size > 0);
|
||||
ptr = realloc(nullptr, size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
header = reinterpret_cast<HookHeader*>((char*)ptr - HOOK_HEADER_SIZE);
|
||||
ASSERT_TRUE(header->from_glibc_ == from_glibc);
|
||||
ASSERT_EQ(header->data_size_, size);
|
||||
// realloc(nullptr, size > 0);
|
||||
ptr = realloc(nullptr, size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
header = Header::ptr2header(ptr);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
ASSERT_EQ(header->data_size_, size);
|
||||
|
||||
// realloc(size zoom in && out);
|
||||
ptr = malloc(size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
header = reinterpret_cast<HookHeader*>((char*)ptr - HOOK_HEADER_SIZE);
|
||||
ASSERT_TRUE(header->from_glibc_ == from_glibc);
|
||||
ASSERT_EQ(header->data_size_, size);
|
||||
// zoom in
|
||||
ptr = realloc(ptr, size * 2);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
header = reinterpret_cast<HookHeader*>((char*)ptr - HOOK_HEADER_SIZE);
|
||||
ASSERT_TRUE(header->from_glibc_ == from_glibc);
|
||||
ASSERT_EQ(header->data_size_, size * 2);
|
||||
// zoom out
|
||||
ptr = realloc(ptr, size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
header = reinterpret_cast<HookHeader*>((char*)ptr - HOOK_HEADER_SIZE);
|
||||
ASSERT_TRUE(header->from_glibc_ == from_glibc);
|
||||
ASSERT_EQ(header->data_size_, size);
|
||||
// realloc(size zoom in && out);
|
||||
ptr = malloc(size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
header = Header::ptr2header(ptr);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
ASSERT_EQ(header->data_size_, size);
|
||||
// zoom in
|
||||
ptr = realloc(ptr, size * 2);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
header = Header::ptr2header(ptr);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
ASSERT_EQ(header->data_size_, size * 2);
|
||||
// zoom out
|
||||
ptr = realloc(ptr, size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
header = Header::ptr2header(ptr);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
ASSERT_EQ(header->data_size_, size);
|
||||
|
||||
// memalign
|
||||
size_t alignment = 4L << 10;
|
||||
ptr = memalign(alignment, size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
ASSERT_EQ(0, (size_t)ptr & (alignment - 1));
|
||||
header = reinterpret_cast<HookHeader*>((char*)ptr - HOOK_HEADER_SIZE);
|
||||
ASSERT_TRUE(header->from_glibc_ == from_glibc);
|
||||
ASSERT_EQ(header->data_size_, size);
|
||||
free(ptr);
|
||||
// memalign
|
||||
size_t alignment = 4L << 10;
|
||||
ptr = memalign(alignment, size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
ASSERT_EQ(0, (size_t)ptr & (alignment - 1));
|
||||
header = Header::ptr2header(ptr);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
ASSERT_EQ(header->data_size_, size);
|
||||
free(ptr);
|
||||
|
||||
// valloc && realloc
|
||||
ptr = valloc(size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
ASSERT_EQ(0, (size_t)ptr & (sysconf(_SC_PAGESIZE) - 1));
|
||||
header = reinterpret_cast<HookHeader*>((char*)ptr - HOOK_HEADER_SIZE);
|
||||
ASSERT_TRUE(header->from_glibc_ == from_glibc);
|
||||
ASSERT_EQ(header->data_size_, size);
|
||||
new_ptr = realloc(ptr, size * 2);
|
||||
header = reinterpret_cast<HookHeader*>((char*)new_ptr - HOOK_HEADER_SIZE);
|
||||
ASSERT_TRUE(header->from_glibc_ == from_glibc);
|
||||
ASSERT_EQ(header->data_size_, size * 2);
|
||||
// valloc && realloc
|
||||
ptr = valloc(size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
ASSERT_EQ(0, (size_t)ptr & (sysconf(_SC_PAGESIZE) - 1));
|
||||
header = Header::ptr2header(ptr);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
ASSERT_EQ(header->data_size_, size);
|
||||
new_ptr = realloc(ptr, size * 2);
|
||||
header = Header::ptr2header(new_ptr);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
ASSERT_EQ(header->data_size_, size * 2);
|
||||
free(new_ptr);
|
||||
|
||||
// posix_memalign
|
||||
posix_memalign(&ptr, 32, size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
free(ptr);
|
||||
}
|
||||
// posix_memalign
|
||||
ret = posix_memalign(&ptr, alignment, size);
|
||||
ASSERT_EQ(0, ret);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
ASSERT_EQ(0, (size_t)ptr & (alignment - 1));
|
||||
free(ptr);
|
||||
|
||||
// free_aligned_sized
|
||||
ptr = aligned_alloc(alignment, size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
ASSERT_EQ(0, (size_t)ptr & (alignment - 1));
|
||||
free(ptr);
|
||||
|
||||
// pvalloc
|
||||
ptr = pvalloc(size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
ASSERT_EQ(0, (size_t)ptr & (sysconf(_SC_PAGESIZE) - 1));
|
||||
header = Header::ptr2header(ptr);
|
||||
ASSERT_EQ(header->data_size_, sysconf(_SC_PAGESIZE));
|
||||
free(ptr);
|
||||
|
||||
// realloc && cross
|
||||
for (int i = 0; i < 2; i++) {
|
||||
lib::glibc_hook_opt = 0 == i ? GHO_NOHOOK : GHO_HOOK;
|
||||
bool from_glibc = 0 == i;
|
||||
void *ptr = malloc(size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
HookHeader *header = reinterpret_cast<HookHeader*>((char*)ptr - HOOK_HEADER_SIZE);
|
||||
ASSERT_TRUE(header->from_glibc_ == from_glibc);
|
||||
char buf[size];
|
||||
memset(buf, 'a', size);
|
||||
memcpy(ptr, buf, size);
|
||||
lib::glibc_hook_opt = 0 == i ? GHO_HOOK : GHO_NOHOOK;
|
||||
void *new_ptr = realloc(ptr, size * 2);
|
||||
ASSERT_NE(new_ptr, nullptr);
|
||||
header = reinterpret_cast<HookHeader*>((char*)new_ptr - HOOK_HEADER_SIZE);
|
||||
ASSERT_TRUE(header->from_glibc_ == !from_glibc);
|
||||
ASSERT_EQ(header->data_size_, size * 2);
|
||||
ASSERT_EQ(0, memcmp(new_ptr, buf, size));
|
||||
lib::glibc_hook_opt = 0 == i ? GHO_NOHOOK : GHO_HOOK;
|
||||
void *ret = realloc(new_ptr, 0);
|
||||
ASSERT_EQ(ret, nullptr);
|
||||
}
|
||||
ptr = malloc(size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
header = Header::ptr2header(ptr);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
memset(buf, 'a', size);
|
||||
memcpy(ptr, buf, size);
|
||||
new_ptr = realloc(ptr, size * 2);
|
||||
ASSERT_NE(new_ptr, nullptr);
|
||||
header = Header::ptr2header(new_ptr);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
ASSERT_EQ(header->data_size_, size * 2);
|
||||
ASSERT_EQ(0, memcmp(new_ptr, buf, size));
|
||||
free(new_ptr);
|
||||
}
|
||||
|
||||
TEST_F(TestMallocHook, test_strdup)
|
||||
{
|
||||
// strdup
|
||||
char *str = strdup("test");
|
||||
HookHeader *header = reinterpret_cast<HookHeader*>((char*)str - HOOK_HEADER_SIZE);
|
||||
ASSERT_EQ(0, strcmp(str, "test"));
|
||||
ASSERT_EQ(header->MAGIC_CODE_, HOOK_MAGIC_CODE);
|
||||
#ifdef NDEBUG
|
||||
memset(header, 0 , sizeof(HookHeader));
|
||||
// Avoid order rearrangement
|
||||
std::cout << str << std::endl;
|
||||
#endif
|
||||
const char *original = "test";
|
||||
char *str = strdup(original);
|
||||
ASSERT_NE(str, nullptr);
|
||||
Header *header = Header::ptr2header(str);
|
||||
ASSERT_EQ(0, strcmp(str, original));
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
free(str);
|
||||
|
||||
// strndup
|
||||
size_t n = 3;
|
||||
str = strndup(original, n);
|
||||
ASSERT_NE(str, nullptr);
|
||||
header = Header::ptr2header(str);
|
||||
ASSERT_EQ(0, strncmp(str, original, n));
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
free(str);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(TestMallocHook, test_malloc_usable_size)
|
||||
{
|
||||
const static size_t size = 100;
|
||||
void *ptr = malloc(size);
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
Header *header = Header::ptr2header(ptr);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
size_t ptr_size = malloc_usable_size(ptr);
|
||||
ASSERT_EQ(size, ptr_size);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
TEST_F(TestMallocHook, test_cpp_operator)
|
||||
{
|
||||
// new && delete
|
||||
int *ptr = new int;
|
||||
ASSERT_NE(ptr, nullptr);
|
||||
Header *header = Header::ptr2header((void *)ptr);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
delete ptr;
|
||||
|
||||
// new[] && delete[]
|
||||
size_t n = 10;
|
||||
int *ptr_array = new int[n];
|
||||
ASSERT_NE(ptr_array, nullptr);
|
||||
header = Header::ptr2header((void *)ptr_array);
|
||||
ASSERT_TRUE(header->check_magic_code());
|
||||
ptr_array[n - 1] = 10;
|
||||
delete[] ptr_array;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user