//===-- 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 #include #include #include #include #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 AllocatorCache; typedef LargeMmapAllocator<> SecondaryAllocator; typedef CombinedAllocator 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");