diff options
Diffstat (limited to 'lib/asan/asan_allocator.h')
| -rw-r--r-- | lib/asan/asan_allocator.h | 147 |
1 files changed, 132 insertions, 15 deletions
diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h index 2aed598538688..cca24edad81fb 100644 --- a/lib/asan/asan_allocator.h +++ b/lib/asan/asan_allocator.h @@ -17,13 +17,76 @@ #include "asan_internal.h" #include "asan_interceptors.h" +#include "sanitizer_common/sanitizer_list.h" + +// We are in the process of transitioning from the old allocator (version 1) +// to a new one (version 2). The change is quite intrusive so both allocators +// will co-exist in the source base for a while. The actual allocator is chosen +// at build time by redefining this macro. +#ifndef ASAN_ALLOCATOR_VERSION +# if ASAN_LINUX && !ASAN_ANDROID +# define ASAN_ALLOCATOR_VERSION 2 +# else +# define ASAN_ALLOCATOR_VERSION 1 +# endif +#endif // ASAN_ALLOCATOR_VERSION namespace __asan { +enum AllocType { + FROM_MALLOC = 1, // Memory block came from malloc, calloc, realloc, etc. + FROM_NEW = 2, // Memory block came from operator new. + FROM_NEW_BR = 3 // Memory block came from operator new [ ] +}; + static const uptr kNumberOfSizeClasses = 255; struct AsanChunk; -class AsanChunkFifoList { +class AsanChunkView { + public: + explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {} + bool IsValid() { return chunk_ != 0; } + uptr Beg(); // first byte of user memory. + uptr End(); // last byte of user memory. + uptr UsedSize(); // size requested by the user. + uptr AllocTid(); + uptr FreeTid(); + void GetAllocStack(StackTrace *stack); + void GetFreeStack(StackTrace *stack); + bool AddrIsInside(uptr addr, uptr access_size, uptr *offset) { + if (addr >= Beg() && (addr + access_size) <= End()) { + *offset = addr - Beg(); + return true; + } + return false; + } + bool AddrIsAtLeft(uptr addr, uptr access_size, uptr *offset) { + (void)access_size; + if (addr < Beg()) { + *offset = Beg() - addr; + return true; + } + return false; + } + bool AddrIsAtRight(uptr addr, uptr access_size, uptr *offset) { + if (addr + access_size >= End()) { + if (addr <= End()) + *offset = 0; + else + *offset = addr - End(); + return true; + } + return false; + } + + private: + AsanChunk *const chunk_; +}; + +AsanChunkView FindHeapChunkByAddress(uptr address); + +// List of AsanChunks with total size. +class AsanChunkFifoList: public IntrusiveList<AsanChunk> { public: explicit AsanChunkFifoList(LinkerInitialized) { } AsanChunkFifoList() { clear(); } @@ -32,25 +95,31 @@ class AsanChunkFifoList { AsanChunk *Pop(); uptr size() { return size_; } void clear() { - first_ = last_ = 0; + IntrusiveList<AsanChunk>::clear(); size_ = 0; } private: - AsanChunk *first_; - AsanChunk *last_; uptr size_; }; struct AsanThreadLocalMallocStorage { explicit AsanThreadLocalMallocStorage(LinkerInitialized x) - : quarantine_(x) { } +#if ASAN_ALLOCATOR_VERSION == 1 + : quarantine_(x) +#endif + { } AsanThreadLocalMallocStorage() { CHECK(REAL(memset)); REAL(memset)(this, 0, sizeof(AsanThreadLocalMallocStorage)); } +#if ASAN_ALLOCATOR_VERSION == 1 AsanChunkFifoList quarantine_; AsanChunk *free_lists_[kNumberOfSizeClasses]; +#else + uptr quarantine_cache[16]; + uptr allocator2_cache[96 * (512 * 8 + 16)]; // Opaque. +#endif void CommitBack(); }; @@ -108,6 +177,7 @@ class FakeStack { // Return the bottom of the maped region. uptr AddrIsInFakeStack(uptr addr); bool StackSize() { return stack_size_; } + private: static const uptr kMinStackFrameSizeLog = 9; // Min frame is 512B. static const uptr kMaxStackFrameSizeLog = 16; // Max stack frame is 64K. @@ -137,23 +207,70 @@ class FakeStack { FakeFrameLifo call_stack_; }; -void *asan_memalign(uptr alignment, uptr size, AsanStackTrace *stack); -void asan_free(void *ptr, AsanStackTrace *stack); +void *asan_memalign(uptr alignment, uptr size, StackTrace *stack, + AllocType alloc_type); +void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type); -void *asan_malloc(uptr size, AsanStackTrace *stack); -void *asan_calloc(uptr nmemb, uptr size, AsanStackTrace *stack); -void *asan_realloc(void *p, uptr size, AsanStackTrace *stack); -void *asan_valloc(uptr size, AsanStackTrace *stack); -void *asan_pvalloc(uptr size, AsanStackTrace *stack); +void *asan_malloc(uptr size, StackTrace *stack); +void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack); +void *asan_realloc(void *p, uptr size, StackTrace *stack); +void *asan_valloc(uptr size, StackTrace *stack); +void *asan_pvalloc(uptr size, StackTrace *stack); int asan_posix_memalign(void **memptr, uptr alignment, uptr size, - AsanStackTrace *stack); -uptr asan_malloc_usable_size(void *ptr, AsanStackTrace *stack); + StackTrace *stack); +uptr asan_malloc_usable_size(void *ptr, StackTrace *stack); uptr asan_mz_size(const void *ptr); void asan_mz_force_lock(); void asan_mz_force_unlock(); -void DescribeHeapAddress(uptr addr, uptr access_size); + +void PrintInternalAllocatorStats(); + +// Log2 and RoundUpToPowerOfTwo should be inlined for performance. +#if defined(_WIN32) && !defined(__clang__) +extern "C" { +unsigned char _BitScanForward(unsigned long *index, unsigned long mask); // NOLINT +unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); // NOLINT +#if defined(_WIN64) +unsigned char _BitScanForward64(unsigned long *index, unsigned __int64 mask); // NOLINT +unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask); // NOLINT +#endif +} +#endif + +static inline uptr Log2(uptr x) { + CHECK(IsPowerOfTwo(x)); +#if !defined(_WIN32) || defined(__clang__) + return __builtin_ctzl(x); +#elif defined(_WIN64) + unsigned long ret; // NOLINT + _BitScanForward64(&ret, x); + return ret; +#else + unsigned long ret; // NOLINT + _BitScanForward(&ret, x); + return ret; +#endif +} + +static inline uptr RoundUpToPowerOfTwo(uptr size) { + CHECK(size); + if (IsPowerOfTwo(size)) return size; + + unsigned long up; // NOLINT +#if !defined(_WIN32) || defined(__clang__) + up = SANITIZER_WORDSIZE - 1 - __builtin_clzl(size); +#elif defined(_WIN64) + _BitScanReverse64(&up, size); +#else + _BitScanReverse(&up, size); +#endif + CHECK(size < (1ULL << (up + 1))); + CHECK(size > (1ULL << up)); + return 1UL << (up + 1); +} + } // namespace __asan #endif // ASAN_ALLOCATOR_H |
