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 19 namespace __msan { 20 21 struct Metadata { 22 uptr requested_size; 23 }; 24 25 static const uptr kAllocatorSpace = 0x600000000000ULL; 26 static const uptr kAllocatorSize = 0x80000000000; // 8T. 27 static const uptr kMetadataSize = sizeof(Metadata); 28 29 typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize, 30 DefaultSizeClassMap> PrimaryAllocator; 31 typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache; 32 typedef LargeMmapAllocator<> SecondaryAllocator; 33 typedef CombinedAllocator<PrimaryAllocator, AllocatorCache, 34 SecondaryAllocator> Allocator; 35 36 static THREADLOCAL AllocatorCache cache; 37 static Allocator allocator; 38 39 static int inited = 0; 40 41 static 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 48 static 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 68 void 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 83 void *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 110 static 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 122 using namespace __msan; 123 124 uptr __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 132 uptr __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 140 uptr __msan_get_free_bytes() { 141 return 1; 142 } 143 144 uptr __msan_get_unmapped_bytes() { 145 return 1; 146 } 147 148 uptr __msan_get_estimated_allocated_size(uptr size) { 149 return size; 150 } 151 152 bool __msan_get_ownership(const void *p) { 153 return AllocationSize(p) != 0; 154 } 155 156 uptr __msan_get_allocated_size(const void *p) { 157 return AllocationSize(p); 158 } 159