re-implement glibc-malloc hooking

This commit is contained in:
gaopy3 2024-11-21 11:48:07 +00:00 committed by ob-robot
parent e1b903be06
commit 467919e950
6 changed files with 540 additions and 197 deletions

View File

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

View File

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

View 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

View File

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

View File

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

View File

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