msan_allocator.cc revision effdc7e483708cfa4dc597c21f246c5dbc09daa0
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), 62 0); // Higher bit is occupied by stack origins. 63 __msan_set_origin(res, size, stack_id); 64 } 65 } 66 MSAN_MALLOC_HOOK(res, size); 67 return res; 68} 69 70void MsanDeallocate(StackTrace *stack, void *p) { 71 CHECK(p); 72 Init(); 73 MSAN_FREE_HOOK(p); 74 Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(p)); 75 uptr size = meta->requested_size; 76 meta->requested_size = 0; 77 // This memory will not be reused by anyone else, so we are free to keep it 78 // poisoned. 79 if (flags()->poison_in_free) { 80 __msan_poison(p, size); 81 if (__msan_get_track_origins()) { 82 u32 stack_id = StackDepotPut(stack->trace, stack->size); 83 CHECK(stack_id); 84 CHECK_EQ((stack_id >> 31), 85 0); // Higher bit is occupied by stack origins. 86 __msan_set_origin(p, size, stack_id); 87 } 88 } 89 allocator.Deallocate(&cache, p); 90} 91 92void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size, 93 uptr alignment, bool zeroise) { 94 if (!old_p) 95 return MsanAllocate(stack, new_size, alignment, zeroise); 96 if (!new_size) { 97 MsanDeallocate(stack, old_p); 98 return 0; 99 } 100 Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(old_p)); 101 uptr old_size = meta->requested_size; 102 uptr actually_allocated_size = allocator.GetActuallyAllocatedSize(old_p); 103 if (new_size <= actually_allocated_size) { 104 // We are not reallocating here. 105 meta->requested_size = new_size; 106 if (new_size > old_size) 107 __msan_poison((char*)old_p + old_size, new_size - old_size); 108 return old_p; 109 } 110 uptr memcpy_size = Min(new_size, old_size); 111 void *new_p = MsanAllocate(stack, new_size, alignment, zeroise); 112 // Printf("realloc: old_size %zd new_size %zd\n", old_size, new_size); 113 if (new_p) 114 __msan_memcpy(new_p, old_p, memcpy_size); 115 MsanDeallocate(stack, old_p); 116 return new_p; 117} 118 119static uptr AllocationSize(const void *p) { 120 if (p == 0) 121 return 0; 122 const void *beg = allocator.GetBlockBegin(p); 123 if (beg != p) 124 return 0; 125 Metadata *b = (Metadata*)allocator.GetMetaData(p); 126 return b->requested_size; 127} 128 129} // namespace __msan 130 131using namespace __msan; 132 133uptr __msan_get_current_allocated_bytes() { 134 u64 stats[AllocatorStatCount]; 135 allocator.GetStats(stats); 136 u64 m = stats[AllocatorStatMalloced]; 137 u64 f = stats[AllocatorStatFreed]; 138 return m >= f ? m - f : 1; 139} 140 141uptr __msan_get_heap_size() { 142 u64 stats[AllocatorStatCount]; 143 allocator.GetStats(stats); 144 u64 m = stats[AllocatorStatMmapped]; 145 u64 f = stats[AllocatorStatUnmapped]; 146 return m >= f ? m - f : 1; 147} 148 149uptr __msan_get_free_bytes() { 150 return 1; 151} 152 153uptr __msan_get_unmapped_bytes() { 154 return 1; 155} 156 157uptr __msan_get_estimated_allocated_size(uptr size) { 158 return size; 159} 160 161int __msan_get_ownership(const void *p) { 162 return AllocationSize(p) != 0; 163} 164 165uptr __msan_get_allocated_size(const void *p) { 166 return AllocationSize(p); 167} 168