| //===-- sanitizer_allocator_testlib.cc ------------------------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // Malloc replacement library based on CombinedAllocator. |
| // The primary purpose of this file is an end-to-end integration test |
| // for CombinedAllocator. |
| //===----------------------------------------------------------------------===// |
| /* Usage: |
| clang++ -std=c++11 -fno-exceptions -g -fPIC -I. -I../include -Isanitizer \ |
| sanitizer_common/tests/sanitizer_allocator_testlib.cc \ |
| $(\ls sanitizer_common/sanitizer_*.cc | grep -v sanitizer_common_nolibc.cc) \ |
| sanitizer_common/sanitizer_linux_x86_64.S \ |
| -shared -lpthread -o testmalloc.so |
| LD_PRELOAD=`pwd`/testmalloc.so /your/app |
| */ |
| #include "sanitizer_common/sanitizer_allocator.h" |
| #include "sanitizer_common/sanitizer_common.h" |
| #include <stddef.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <pthread.h> |
| |
| #ifndef SANITIZER_MALLOC_HOOK |
| # define SANITIZER_MALLOC_HOOK(p, s) |
| #endif |
| |
| #ifndef SANITIZER_FREE_HOOK |
| # define SANITIZER_FREE_HOOK(p) |
| #endif |
| |
| static const uptr kAllocatorSpace = 0x600000000000ULL; |
| static const uptr kAllocatorSize = 0x10000000000ULL; // 1T. |
| |
| struct __AP64 { |
| static const uptr kSpaceBeg = ~(uptr)0; |
| static const uptr kSpaceSize = kAllocatorSize; |
| static const uptr kMetadataSize = 0; |
| typedef CompactSizeClassMap SizeClassMap; |
| typedef NoOpMapUnmapCallback MapUnmapCallback; |
| static const uptr kFlags = |
| SizeClassAllocator64FlagMasks::kRandomShuffleChunks; |
| }; |
| |
| namespace { |
| |
| typedef SizeClassAllocator64<__AP64> PrimaryAllocator; |
| typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache; |
| typedef LargeMmapAllocator<> SecondaryAllocator; |
| typedef CombinedAllocator<PrimaryAllocator, AllocatorCache, |
| SecondaryAllocator> Allocator; |
| |
| static Allocator allocator; |
| static bool global_inited; |
| static THREADLOCAL AllocatorCache cache; |
| static THREADLOCAL bool thread_inited; |
| static pthread_key_t pkey; |
| |
| static void thread_dtor(void *v) { |
| if ((uptr)v != 3) { |
| pthread_setspecific(pkey, (void*)((uptr)v + 1)); |
| return; |
| } |
| allocator.SwallowCache(&cache); |
| } |
| |
| static size_t GetRss() { |
| if (FILE *f = fopen("/proc/self/statm", "r")) { |
| size_t size = 0, rss = 0; |
| fscanf(f, "%zd %zd", &size, &rss); |
| fclose(f); |
| return rss << 12; // rss is in pages. |
| } |
| return 0; |
| } |
| |
| struct AtExit { |
| ~AtExit() { |
| allocator.PrintStats(); |
| Printf("RSS: %zdM\n", GetRss() >> 20); |
| } |
| }; |
| |
| static AtExit at_exit; |
| |
| static void NOINLINE thread_init() { |
| if (!global_inited) { |
| global_inited = true; |
| allocator.Init(false /*may_return_null*/); |
| pthread_key_create(&pkey, thread_dtor); |
| } |
| thread_inited = true; |
| pthread_setspecific(pkey, (void*)1); |
| cache.Init(nullptr); |
| } |
| } // namespace |
| |
| extern "C" { |
| void *malloc(size_t size) { |
| if (UNLIKELY(!thread_inited)) |
| thread_init(); |
| void *p = allocator.Allocate(&cache, size, 8); |
| SANITIZER_MALLOC_HOOK(p, size); |
| return p; |
| } |
| |
| void free(void *p) { |
| if (UNLIKELY(!thread_inited)) |
| thread_init(); |
| SANITIZER_FREE_HOOK(p); |
| allocator.Deallocate(&cache, p); |
| } |
| |
| void *calloc(size_t nmemb, size_t size) { |
| if (UNLIKELY(!thread_inited)) |
| thread_init(); |
| size *= nmemb; |
| void *p = allocator.Allocate(&cache, size, 8, false); |
| memset(p, 0, size); |
| SANITIZER_MALLOC_HOOK(p, size); |
| return p; |
| } |
| |
| void *realloc(void *p, size_t size) { |
| if (UNLIKELY(!thread_inited)) |
| thread_init(); |
| if (p) { |
| SANITIZER_FREE_HOOK(p); |
| } |
| p = allocator.Reallocate(&cache, p, size, 8); |
| if (p) { |
| SANITIZER_MALLOC_HOOK(p, size); |
| } |
| return p; |
| } |
| |
| #if SANITIZER_INTERCEPT_MEMALIGN |
| void *memalign(size_t alignment, size_t size) { |
| if (UNLIKELY(!thread_inited)) |
| thread_init(); |
| void *p = allocator.Allocate(&cache, size, alignment); |
| SANITIZER_MALLOC_HOOK(p, size); |
| return p; |
| } |
| #endif // SANITIZER_INTERCEPT_MEMALIGN |
| |
| int posix_memalign(void **memptr, size_t alignment, size_t size) { |
| if (UNLIKELY(!thread_inited)) |
| thread_init(); |
| *memptr = allocator.Allocate(&cache, size, alignment); |
| SANITIZER_MALLOC_HOOK(*memptr, size); |
| return 0; |
| } |
| |
| void *valloc(size_t size) { |
| if (UNLIKELY(!thread_inited)) |
| thread_init(); |
| if (size == 0) |
| size = GetPageSizeCached(); |
| void *p = allocator.Allocate(&cache, size, GetPageSizeCached()); |
| SANITIZER_MALLOC_HOOK(p, size); |
| return p; |
| } |
| |
| #if SANITIZER_INTERCEPT_CFREE |
| void cfree(void *p) ALIAS("free"); |
| #endif // SANITIZER_INTERCEPT_CFREE |
| #if SANITIZER_INTERCEPT_PVALLOC |
| void *pvalloc(size_t size) ALIAS("valloc"); |
| #endif // SANITIZER_INTERCEPT_PVALLOC |
| #if SANITIZER_INTERCEPT_MEMALIGN |
| void *__libc_memalign(size_t alignment, size_t size) ALIAS("memalign"); |
| #endif // SANITIZER_INTERCEPT_MEMALIGN |
| |
| void malloc_usable_size() { |
| } |
| |
| #if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO |
| void mallinfo() { |
| } |
| |
| void mallopt() { |
| } |
| #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO |
| } // extern "C" |
| |
| namespace std { |
| struct nothrow_t; |
| } |
| |
| void *operator new(size_t size) ALIAS("malloc"); |
| void *operator new[](size_t size) ALIAS("malloc"); |
| void *operator new(size_t size, std::nothrow_t const&) ALIAS("malloc"); |
| void *operator new[](size_t size, std::nothrow_t const&) ALIAS("malloc"); |
| void operator delete(void *ptr) throw() ALIAS("free"); |
| void operator delete[](void *ptr) throw() ALIAS("free"); |
| void operator delete(void *ptr, std::nothrow_t const&) ALIAS("free"); |
| void operator delete[](void *ptr, std::nothrow_t const&) ALIAS("free"); |