1*7c3d14c8STreehugger Robot //===-- msan_allocator.cc --------------------------- ---------------------===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot // The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // This file is a part of MemorySanitizer.
11*7c3d14c8STreehugger Robot //
12*7c3d14c8STreehugger Robot // MemorySanitizer allocator.
13*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
14*7c3d14c8STreehugger Robot
15*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_allocator.h"
16*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_allocator_interface.h"
17*7c3d14c8STreehugger Robot #include "msan.h"
18*7c3d14c8STreehugger Robot #include "msan_allocator.h"
19*7c3d14c8STreehugger Robot #include "msan_origin.h"
20*7c3d14c8STreehugger Robot #include "msan_thread.h"
21*7c3d14c8STreehugger Robot #include "msan_poisoning.h"
22*7c3d14c8STreehugger Robot
23*7c3d14c8STreehugger Robot namespace __msan {
24*7c3d14c8STreehugger Robot
25*7c3d14c8STreehugger Robot struct Metadata {
26*7c3d14c8STreehugger Robot uptr requested_size;
27*7c3d14c8STreehugger Robot };
28*7c3d14c8STreehugger Robot
29*7c3d14c8STreehugger Robot struct MsanMapUnmapCallback {
OnMap__msan::MsanMapUnmapCallback30*7c3d14c8STreehugger Robot void OnMap(uptr p, uptr size) const {}
OnUnmap__msan::MsanMapUnmapCallback31*7c3d14c8STreehugger Robot void OnUnmap(uptr p, uptr size) const {
32*7c3d14c8STreehugger Robot __msan_unpoison((void *)p, size);
33*7c3d14c8STreehugger Robot
34*7c3d14c8STreehugger Robot // We are about to unmap a chunk of user memory.
35*7c3d14c8STreehugger Robot // Mark the corresponding shadow memory as not needed.
36*7c3d14c8STreehugger Robot FlushUnneededShadowMemory(MEM_TO_SHADOW(p), size);
37*7c3d14c8STreehugger Robot if (__msan_get_track_origins())
38*7c3d14c8STreehugger Robot FlushUnneededShadowMemory(MEM_TO_ORIGIN(p), size);
39*7c3d14c8STreehugger Robot }
40*7c3d14c8STreehugger Robot };
41*7c3d14c8STreehugger Robot
42*7c3d14c8STreehugger Robot #if defined(__mips64)
43*7c3d14c8STreehugger Robot static const uptr kMaxAllowedMallocSize = 2UL << 30;
44*7c3d14c8STreehugger Robot static const uptr kRegionSizeLog = 20;
45*7c3d14c8STreehugger Robot static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
46*7c3d14c8STreehugger Robot typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
47*7c3d14c8STreehugger Robot typedef CompactSizeClassMap SizeClassMap;
48*7c3d14c8STreehugger Robot
49*7c3d14c8STreehugger Robot typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(Metadata),
50*7c3d14c8STreehugger Robot SizeClassMap, kRegionSizeLog, ByteMap,
51*7c3d14c8STreehugger Robot MsanMapUnmapCallback> PrimaryAllocator;
52*7c3d14c8STreehugger Robot
53*7c3d14c8STreehugger Robot #elif defined(__x86_64__)
54*7c3d14c8STreehugger Robot #if SANITIZER_LINUX && !defined(MSAN_LINUX_X86_64_OLD_MAPPING)
55*7c3d14c8STreehugger Robot static const uptr kAllocatorSpace = 0x700000000000ULL;
56*7c3d14c8STreehugger Robot #else
57*7c3d14c8STreehugger Robot static const uptr kAllocatorSpace = 0x600000000000ULL;
58*7c3d14c8STreehugger Robot #endif
59*7c3d14c8STreehugger Robot static const uptr kAllocatorSize = 0x80000000000; // 8T.
60*7c3d14c8STreehugger Robot static const uptr kMetadataSize = sizeof(Metadata);
61*7c3d14c8STreehugger Robot static const uptr kMaxAllowedMallocSize = 8UL << 30;
62*7c3d14c8STreehugger Robot
63*7c3d14c8STreehugger Robot typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize,
64*7c3d14c8STreehugger Robot DefaultSizeClassMap,
65*7c3d14c8STreehugger Robot MsanMapUnmapCallback> PrimaryAllocator;
66*7c3d14c8STreehugger Robot
67*7c3d14c8STreehugger Robot #elif defined(__powerpc64__)
68*7c3d14c8STreehugger Robot static const uptr kAllocatorSpace = 0x300000000000;
69*7c3d14c8STreehugger Robot static const uptr kAllocatorSize = 0x020000000000; // 2T
70*7c3d14c8STreehugger Robot static const uptr kMetadataSize = sizeof(Metadata);
71*7c3d14c8STreehugger Robot static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G
72*7c3d14c8STreehugger Robot
73*7c3d14c8STreehugger Robot typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize,
74*7c3d14c8STreehugger Robot DefaultSizeClassMap,
75*7c3d14c8STreehugger Robot MsanMapUnmapCallback> PrimaryAllocator;
76*7c3d14c8STreehugger Robot #elif defined(__aarch64__)
77*7c3d14c8STreehugger Robot static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G
78*7c3d14c8STreehugger Robot static const uptr kRegionSizeLog = 20;
79*7c3d14c8STreehugger Robot static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
80*7c3d14c8STreehugger Robot typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
81*7c3d14c8STreehugger Robot typedef CompactSizeClassMap SizeClassMap;
82*7c3d14c8STreehugger Robot
83*7c3d14c8STreehugger Robot typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(Metadata),
84*7c3d14c8STreehugger Robot SizeClassMap, kRegionSizeLog, ByteMap,
85*7c3d14c8STreehugger Robot MsanMapUnmapCallback> PrimaryAllocator;
86*7c3d14c8STreehugger Robot #endif
87*7c3d14c8STreehugger Robot typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
88*7c3d14c8STreehugger Robot typedef LargeMmapAllocator<MsanMapUnmapCallback> SecondaryAllocator;
89*7c3d14c8STreehugger Robot typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
90*7c3d14c8STreehugger Robot SecondaryAllocator> Allocator;
91*7c3d14c8STreehugger Robot
92*7c3d14c8STreehugger Robot static Allocator allocator;
93*7c3d14c8STreehugger Robot static AllocatorCache fallback_allocator_cache;
94*7c3d14c8STreehugger Robot static SpinMutex fallback_mutex;
95*7c3d14c8STreehugger Robot
MsanAllocatorInit()96*7c3d14c8STreehugger Robot void MsanAllocatorInit() {
97*7c3d14c8STreehugger Robot allocator.Init(common_flags()->allocator_may_return_null);
98*7c3d14c8STreehugger Robot }
99*7c3d14c8STreehugger Robot
GetAllocatorCache(MsanThreadLocalMallocStorage * ms)100*7c3d14c8STreehugger Robot AllocatorCache *GetAllocatorCache(MsanThreadLocalMallocStorage *ms) {
101*7c3d14c8STreehugger Robot CHECK(ms);
102*7c3d14c8STreehugger Robot CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator_cache));
103*7c3d14c8STreehugger Robot return reinterpret_cast<AllocatorCache *>(ms->allocator_cache);
104*7c3d14c8STreehugger Robot }
105*7c3d14c8STreehugger Robot
CommitBack()106*7c3d14c8STreehugger Robot void MsanThreadLocalMallocStorage::CommitBack() {
107*7c3d14c8STreehugger Robot allocator.SwallowCache(GetAllocatorCache(this));
108*7c3d14c8STreehugger Robot }
109*7c3d14c8STreehugger Robot
MsanAllocate(StackTrace * stack,uptr size,uptr alignment,bool zeroise)110*7c3d14c8STreehugger Robot static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,
111*7c3d14c8STreehugger Robot bool zeroise) {
112*7c3d14c8STreehugger Robot if (size > kMaxAllowedMallocSize) {
113*7c3d14c8STreehugger Robot Report("WARNING: MemorySanitizer failed to allocate %p bytes\n",
114*7c3d14c8STreehugger Robot (void *)size);
115*7c3d14c8STreehugger Robot return allocator.ReturnNullOrDie();
116*7c3d14c8STreehugger Robot }
117*7c3d14c8STreehugger Robot MsanThread *t = GetCurrentThread();
118*7c3d14c8STreehugger Robot void *allocated;
119*7c3d14c8STreehugger Robot if (t) {
120*7c3d14c8STreehugger Robot AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
121*7c3d14c8STreehugger Robot allocated = allocator.Allocate(cache, size, alignment, false);
122*7c3d14c8STreehugger Robot } else {
123*7c3d14c8STreehugger Robot SpinMutexLock l(&fallback_mutex);
124*7c3d14c8STreehugger Robot AllocatorCache *cache = &fallback_allocator_cache;
125*7c3d14c8STreehugger Robot allocated = allocator.Allocate(cache, size, alignment, false);
126*7c3d14c8STreehugger Robot }
127*7c3d14c8STreehugger Robot Metadata *meta =
128*7c3d14c8STreehugger Robot reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
129*7c3d14c8STreehugger Robot meta->requested_size = size;
130*7c3d14c8STreehugger Robot if (zeroise) {
131*7c3d14c8STreehugger Robot __msan_clear_and_unpoison(allocated, size);
132*7c3d14c8STreehugger Robot } else if (flags()->poison_in_malloc) {
133*7c3d14c8STreehugger Robot __msan_poison(allocated, size);
134*7c3d14c8STreehugger Robot if (__msan_get_track_origins()) {
135*7c3d14c8STreehugger Robot stack->tag = StackTrace::TAG_ALLOC;
136*7c3d14c8STreehugger Robot Origin o = Origin::CreateHeapOrigin(stack);
137*7c3d14c8STreehugger Robot __msan_set_origin(allocated, size, o.raw_id());
138*7c3d14c8STreehugger Robot }
139*7c3d14c8STreehugger Robot }
140*7c3d14c8STreehugger Robot MSAN_MALLOC_HOOK(allocated, size);
141*7c3d14c8STreehugger Robot return allocated;
142*7c3d14c8STreehugger Robot }
143*7c3d14c8STreehugger Robot
MsanDeallocate(StackTrace * stack,void * p)144*7c3d14c8STreehugger Robot void MsanDeallocate(StackTrace *stack, void *p) {
145*7c3d14c8STreehugger Robot CHECK(p);
146*7c3d14c8STreehugger Robot MSAN_FREE_HOOK(p);
147*7c3d14c8STreehugger Robot Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(p));
148*7c3d14c8STreehugger Robot uptr size = meta->requested_size;
149*7c3d14c8STreehugger Robot meta->requested_size = 0;
150*7c3d14c8STreehugger Robot // This memory will not be reused by anyone else, so we are free to keep it
151*7c3d14c8STreehugger Robot // poisoned.
152*7c3d14c8STreehugger Robot if (flags()->poison_in_free) {
153*7c3d14c8STreehugger Robot __msan_poison(p, size);
154*7c3d14c8STreehugger Robot if (__msan_get_track_origins()) {
155*7c3d14c8STreehugger Robot stack->tag = StackTrace::TAG_DEALLOC;
156*7c3d14c8STreehugger Robot Origin o = Origin::CreateHeapOrigin(stack);
157*7c3d14c8STreehugger Robot __msan_set_origin(p, size, o.raw_id());
158*7c3d14c8STreehugger Robot }
159*7c3d14c8STreehugger Robot }
160*7c3d14c8STreehugger Robot MsanThread *t = GetCurrentThread();
161*7c3d14c8STreehugger Robot if (t) {
162*7c3d14c8STreehugger Robot AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
163*7c3d14c8STreehugger Robot allocator.Deallocate(cache, p);
164*7c3d14c8STreehugger Robot } else {
165*7c3d14c8STreehugger Robot SpinMutexLock l(&fallback_mutex);
166*7c3d14c8STreehugger Robot AllocatorCache *cache = &fallback_allocator_cache;
167*7c3d14c8STreehugger Robot allocator.Deallocate(cache, p);
168*7c3d14c8STreehugger Robot }
169*7c3d14c8STreehugger Robot }
170*7c3d14c8STreehugger Robot
MsanCalloc(StackTrace * stack,uptr nmemb,uptr size)171*7c3d14c8STreehugger Robot void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
172*7c3d14c8STreehugger Robot if (CallocShouldReturnNullDueToOverflow(size, nmemb))
173*7c3d14c8STreehugger Robot return allocator.ReturnNullOrDie();
174*7c3d14c8STreehugger Robot return MsanReallocate(stack, nullptr, nmemb * size, sizeof(u64), true);
175*7c3d14c8STreehugger Robot }
176*7c3d14c8STreehugger Robot
MsanReallocate(StackTrace * stack,void * old_p,uptr new_size,uptr alignment,bool zeroise)177*7c3d14c8STreehugger Robot void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size,
178*7c3d14c8STreehugger Robot uptr alignment, bool zeroise) {
179*7c3d14c8STreehugger Robot if (!old_p)
180*7c3d14c8STreehugger Robot return MsanAllocate(stack, new_size, alignment, zeroise);
181*7c3d14c8STreehugger Robot if (!new_size) {
182*7c3d14c8STreehugger Robot MsanDeallocate(stack, old_p);
183*7c3d14c8STreehugger Robot return nullptr;
184*7c3d14c8STreehugger Robot }
185*7c3d14c8STreehugger Robot Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(old_p));
186*7c3d14c8STreehugger Robot uptr old_size = meta->requested_size;
187*7c3d14c8STreehugger Robot uptr actually_allocated_size = allocator.GetActuallyAllocatedSize(old_p);
188*7c3d14c8STreehugger Robot if (new_size <= actually_allocated_size) {
189*7c3d14c8STreehugger Robot // We are not reallocating here.
190*7c3d14c8STreehugger Robot meta->requested_size = new_size;
191*7c3d14c8STreehugger Robot if (new_size > old_size) {
192*7c3d14c8STreehugger Robot if (zeroise) {
193*7c3d14c8STreehugger Robot __msan_clear_and_unpoison((char *)old_p + old_size,
194*7c3d14c8STreehugger Robot new_size - old_size);
195*7c3d14c8STreehugger Robot } else if (flags()->poison_in_malloc) {
196*7c3d14c8STreehugger Robot stack->tag = StackTrace::TAG_ALLOC;
197*7c3d14c8STreehugger Robot PoisonMemory((char *)old_p + old_size, new_size - old_size, stack);
198*7c3d14c8STreehugger Robot }
199*7c3d14c8STreehugger Robot }
200*7c3d14c8STreehugger Robot return old_p;
201*7c3d14c8STreehugger Robot }
202*7c3d14c8STreehugger Robot uptr memcpy_size = Min(new_size, old_size);
203*7c3d14c8STreehugger Robot void *new_p = MsanAllocate(stack, new_size, alignment, zeroise);
204*7c3d14c8STreehugger Robot // Printf("realloc: old_size %zd new_size %zd\n", old_size, new_size);
205*7c3d14c8STreehugger Robot if (new_p) {
206*7c3d14c8STreehugger Robot CopyMemory(new_p, old_p, memcpy_size, stack);
207*7c3d14c8STreehugger Robot MsanDeallocate(stack, old_p);
208*7c3d14c8STreehugger Robot }
209*7c3d14c8STreehugger Robot return new_p;
210*7c3d14c8STreehugger Robot }
211*7c3d14c8STreehugger Robot
AllocationSize(const void * p)212*7c3d14c8STreehugger Robot static uptr AllocationSize(const void *p) {
213*7c3d14c8STreehugger Robot if (!p) return 0;
214*7c3d14c8STreehugger Robot const void *beg = allocator.GetBlockBegin(p);
215*7c3d14c8STreehugger Robot if (beg != p) return 0;
216*7c3d14c8STreehugger Robot Metadata *b = (Metadata *)allocator.GetMetaData(p);
217*7c3d14c8STreehugger Robot return b->requested_size;
218*7c3d14c8STreehugger Robot }
219*7c3d14c8STreehugger Robot
220*7c3d14c8STreehugger Robot } // namespace __msan
221*7c3d14c8STreehugger Robot
222*7c3d14c8STreehugger Robot using namespace __msan;
223*7c3d14c8STreehugger Robot
__sanitizer_get_current_allocated_bytes()224*7c3d14c8STreehugger Robot uptr __sanitizer_get_current_allocated_bytes() {
225*7c3d14c8STreehugger Robot uptr stats[AllocatorStatCount];
226*7c3d14c8STreehugger Robot allocator.GetStats(stats);
227*7c3d14c8STreehugger Robot return stats[AllocatorStatAllocated];
228*7c3d14c8STreehugger Robot }
229*7c3d14c8STreehugger Robot
__sanitizer_get_heap_size()230*7c3d14c8STreehugger Robot uptr __sanitizer_get_heap_size() {
231*7c3d14c8STreehugger Robot uptr stats[AllocatorStatCount];
232*7c3d14c8STreehugger Robot allocator.GetStats(stats);
233*7c3d14c8STreehugger Robot return stats[AllocatorStatMapped];
234*7c3d14c8STreehugger Robot }
235*7c3d14c8STreehugger Robot
__sanitizer_get_free_bytes()236*7c3d14c8STreehugger Robot uptr __sanitizer_get_free_bytes() { return 1; }
237*7c3d14c8STreehugger Robot
__sanitizer_get_unmapped_bytes()238*7c3d14c8STreehugger Robot uptr __sanitizer_get_unmapped_bytes() { return 1; }
239*7c3d14c8STreehugger Robot
__sanitizer_get_estimated_allocated_size(uptr size)240*7c3d14c8STreehugger Robot uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
241*7c3d14c8STreehugger Robot
__sanitizer_get_ownership(const void * p)242*7c3d14c8STreehugger Robot int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; }
243*7c3d14c8STreehugger Robot
__sanitizer_get_allocated_size(const void * p)244*7c3d14c8STreehugger Robot uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); }
245