1//===-- msan_allocator.cc --------------------------- ---------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file is a part of MemorySanitizer. 11// 12// MemorySanitizer allocator. 13//===----------------------------------------------------------------------===// 14 15#include "sanitizer_common/sanitizer_allocator.h" 16#include "sanitizer_common/sanitizer_stackdepot.h" 17#include "msan.h" 18 19namespace __msan { 20 21struct Metadata { 22 uptr requested_size; 23}; 24 25static const uptr kAllocatorSpace = 0x600000000000ULL; 26static const uptr kAllocatorSize = 0x80000000000; // 8T. 27static const uptr kMetadataSize = sizeof(Metadata); 28 29typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize, 30 DefaultSizeClassMap> PrimaryAllocator; 31typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache; 32typedef LargeMmapAllocator<> SecondaryAllocator; 33typedef CombinedAllocator<PrimaryAllocator, AllocatorCache, 34 SecondaryAllocator> Allocator; 35 36static THREADLOCAL AllocatorCache cache; 37static Allocator allocator; 38 39static int inited = 0; 40 41static inline void Init() { 42 if (inited) return; 43 __msan_init(); 44 inited = true; // this must happen before any threads are created. 45 allocator.Init(); 46} 47 48static void *MsanAllocate(StackTrace *stack, uptr size, 49 uptr alignment, bool zeroise) { 50 Init(); 51 void *res = allocator.Allocate(&cache, size, alignment, false); 52 Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(res)); 53 meta->requested_size = size; 54 if (zeroise) 55 __msan_clear_and_unpoison(res, size); 56 else if (flags()->poison_in_malloc) 57 __msan_poison(res, size); 58 if (__msan_get_track_origins()) { 59 u32 stack_id = StackDepotPut(stack->trace, stack->size); 60 CHECK(stack_id); 61 CHECK_EQ((stack_id >> 31), 0); // Higher bit is occupied by stack origins. 62 __msan_set_origin(res, size, stack_id); 63 } 64 MSAN_MALLOC_HOOK(res, size); 65 return res; 66} 67 68void MsanDeallocate(void *p) { 69 CHECK(p); 70 Init(); 71 MSAN_FREE_HOOK(p); 72 Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(p)); 73 uptr size = meta->requested_size; 74 meta->requested_size = 0; 75 // This memory will not be reused by anyone else, so we are free to keep it 76 // poisoned. 77 __msan_poison(p, size); 78 if (__msan_get_track_origins()) 79 __msan_set_origin(p, size, -1); 80 allocator.Deallocate(&cache, p); 81} 82 83void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size, 84 uptr alignment, bool zeroise) { 85 if (!old_p) 86 return MsanAllocate(stack, new_size, alignment, zeroise); 87 if (!new_size) { 88 MsanDeallocate(old_p); 89 return 0; 90 } 91 Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(old_p)); 92 uptr old_size = meta->requested_size; 93 uptr actually_allocated_size = allocator.GetActuallyAllocatedSize(old_p); 94 if (new_size <= actually_allocated_size) { 95 // We are not reallocating here. 96 meta->requested_size = new_size; 97 if (new_size > old_size) 98 __msan_poison((char*)old_p + old_size, new_size - old_size); 99 return old_p; 100 } 101 uptr memcpy_size = Min(new_size, old_size); 102 void *new_p = MsanAllocate(stack, new_size, alignment, zeroise); 103 // Printf("realloc: old_size %zd new_size %zd\n", old_size, new_size); 104 if (new_p) 105 __msan_memcpy(new_p, old_p, memcpy_size); 106 MsanDeallocate(old_p); 107 return new_p; 108} 109 110static uptr AllocationSize(const void *p) { 111 if (p == 0) 112 return 0; 113 const void *beg = allocator.GetBlockBegin(p); 114 if (beg != p) 115 return 0; 116 Metadata *b = (Metadata*)allocator.GetMetaData(p); 117 return b->requested_size; 118} 119 120} // namespace __msan 121 122using namespace __msan; 123 124uptr __msan_get_current_allocated_bytes() { 125 u64 stats[AllocatorStatCount]; 126 allocator.GetStats(stats); 127 u64 m = stats[AllocatorStatMalloced]; 128 u64 f = stats[AllocatorStatFreed]; 129 return m >= f ? m - f : 1; 130} 131 132uptr __msan_get_heap_size() { 133 u64 stats[AllocatorStatCount]; 134 allocator.GetStats(stats); 135 u64 m = stats[AllocatorStatMmapped]; 136 u64 f = stats[AllocatorStatUnmapped]; 137 return m >= f ? m - f : 1; 138} 139 140uptr __msan_get_free_bytes() { 141 return 1; 142} 143 144uptr __msan_get_unmapped_bytes() { 145 return 1; 146} 147 148uptr __msan_get_estimated_allocated_size(uptr size) { 149 return size; 150} 151 152bool __msan_get_ownership(const void *p) { 153 return AllocationSize(p) != 0; 154} 155 156uptr __msan_get_allocated_size(const void *p) { 157 return AllocationSize(p); 158} 159