Index: lib/asan/asan_malloc_linux.cc =================================================================== --- lib/asan/asan_malloc_linux.cc +++ lib/asan/asan_malloc_linux.cc @@ -22,25 +22,79 @@ #include "asan_interceptors.h" #include "asan_internal.h" #include "asan_stack.h" +#include "sanitizer_common/sanitizer_posix.h" // ---------------------- Replacement functions ---------------- {{{1 using namespace __asan; // NOLINT -static uptr allocated_for_dlsym; -static const uptr kDlsymAllocPoolSize = 1024; -static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; +// struct which represents chunk +struct chunk { + // address of the memory + uptr mem; + // size of the allocated memory aligned to pagesize + uptr size; +}; + +static bool pool_inited = false; +static uptr last_chunk_index; +static uptr last_chunk_offset; +static const uptr kDlsymAllocPoolSize = 16; +static struct chunk alloc_memory_for_dlsym[kDlsymAllocPoolSize]; + +static bool ChunkContainsPtr(uptr index, const void *ptr) { + return alloc_memory_for_dlsym[index].mem <= (uptr)ptr && + (uptr)ptr < alloc_memory_for_dlsym[index].mem + + alloc_memory_for_dlsym[index].size; +} + +// Searching for the index of the chunk which contains asked pointer. +// If ptr doesn't belong to the pool function returns -1 +static int GetChunkIndex(const void *ptr) { + for (uptr index = 0; index <= last_chunk_index; ++index) { + if (ChunkContainsPtr(index, ptr)) + return index; + } + return -1; +} static bool IsInDlsymAllocPool(const void *ptr) { - uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym; - return off < sizeof(alloc_memory_for_dlsym); + if (pool_inited) + return GetChunkIndex(ptr) != -1; + return false; +} + +// Allocate enough memory for the one chunk +static void doAllocateNewChunk(uptr size_in_bytes) { + const uptr asksize = RoundUpTo(size_in_bytes, GetPageSizeCached()); + alloc_memory_for_dlsym[last_chunk_index].mem = + (uptr)MmapOrDie(asksize, "alloc for dlsym pool"); + alloc_memory_for_dlsym[last_chunk_index].size = asksize; +} + +// At the first time when we using local pool we don't have any free +// memory inside. In this case we have to init first chunk at the begining. +static void InitPool(uptr size_in_bytes) { + doAllocateNewChunk(size_in_bytes); + pool_inited = true; } static void *AllocateFromLocalPool(uptr size_in_bytes) { - uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize; - void *mem = (void*)&alloc_memory_for_dlsym[allocated_for_dlsym]; - allocated_for_dlsym += size_in_words; - CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize); - return mem; + if (UNLIKELY(!pool_inited)) + // Init first chunk at the begining anyway + InitPool(size_in_bytes); + const uptr chunk_size = alloc_memory_for_dlsym[last_chunk_index].size; + if (UNLIKELY(size_in_bytes > chunk_size - last_chunk_offset)) { + // In this case we have to allocate memory for new chunk + ++last_chunk_index; + CHECK_LT(last_chunk_index, kDlsymAllocPoolSize); + doAllocateNewChunk(size_in_bytes); + last_chunk_offset = size_in_bytes; + return (void *)alloc_memory_for_dlsym[last_chunk_index].mem; + } + // if we have enough space, use last chunk again + const uptr offset = last_chunk_offset; + last_chunk_offset += size_in_bytes; + return (void *)(alloc_memory_for_dlsym[last_chunk_index].mem + offset); } INTERCEPTOR(void, free, void *ptr) { @@ -78,15 +132,12 @@ INTERCEPTOR(void*, realloc, void *ptr, uptr size) { GET_STACK_TRACE_MALLOC; if (UNLIKELY(IsInDlsymAllocPool(ptr))) { - uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym; - uptr copy_size = Min(size, kDlsymAllocPoolSize - offset); - void *new_ptr; - if (UNLIKELY(!asan_inited)) { - new_ptr = AllocateFromLocalPool(size); - } else { - copy_size = size; - new_ptr = asan_malloc(copy_size, &stack); - } + const int index = GetChunkIndex(ptr); + const uptr offset = (uptr)ptr - alloc_memory_for_dlsym[index].mem; + const uptr copy_size = + Min(size, alloc_memory_for_dlsym[index].size - offset); + void *new_ptr = LIKELY(asan_inited) ? asan_malloc(size, &stack) + : AllocateFromLocalPool(size); internal_memcpy(new_ptr, ptr, copy_size); return new_ptr; }