xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/msan/msan_allocator.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
168d75effSDimitry Andric //===-- msan_allocator.cpp -------------------------- ---------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of MemorySanitizer.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // MemorySanitizer allocator.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1406c3fb27SDimitry Andric #include "msan_allocator.h"
1506c3fb27SDimitry Andric 
1606c3fb27SDimitry Andric #include "msan.h"
1706c3fb27SDimitry Andric #include "msan_interface_internal.h"
1806c3fb27SDimitry Andric #include "msan_origin.h"
1906c3fb27SDimitry Andric #include "msan_poisoning.h"
2006c3fb27SDimitry Andric #include "msan_thread.h"
2168d75effSDimitry Andric #include "sanitizer_common/sanitizer_allocator.h"
2268d75effSDimitry Andric #include "sanitizer_common/sanitizer_allocator_checks.h"
2368d75effSDimitry Andric #include "sanitizer_common/sanitizer_allocator_interface.h"
2468d75effSDimitry Andric #include "sanitizer_common/sanitizer_allocator_report.h"
2568d75effSDimitry Andric #include "sanitizer_common/sanitizer_errno.h"
2668d75effSDimitry Andric 
2768d75effSDimitry Andric namespace __msan {
2868d75effSDimitry Andric 
2968d75effSDimitry Andric struct Metadata {
3068d75effSDimitry Andric   uptr requested_size;
3168d75effSDimitry Andric };
3268d75effSDimitry Andric 
3368d75effSDimitry Andric struct MsanMapUnmapCallback {
3468d75effSDimitry Andric   void OnMap(uptr p, uptr size) const {}
3506c3fb27SDimitry Andric   void OnMapSecondary(uptr p, uptr size, uptr user_begin,
3606c3fb27SDimitry Andric                       uptr user_size) const {}
3768d75effSDimitry Andric   void OnUnmap(uptr p, uptr size) const {
3868d75effSDimitry Andric     __msan_unpoison((void *)p, size);
3968d75effSDimitry Andric 
4068d75effSDimitry Andric     // We are about to unmap a chunk of user memory.
4168d75effSDimitry Andric     // Mark the corresponding shadow memory as not needed.
4268d75effSDimitry Andric     uptr shadow_p = MEM_TO_SHADOW(p);
4368d75effSDimitry Andric     ReleaseMemoryPagesToOS(shadow_p, shadow_p + size);
4468d75effSDimitry Andric     if (__msan_get_track_origins()) {
4568d75effSDimitry Andric       uptr origin_p = MEM_TO_ORIGIN(p);
4668d75effSDimitry Andric       ReleaseMemoryPagesToOS(origin_p, origin_p + size);
4768d75effSDimitry Andric     }
4868d75effSDimitry Andric   }
4968d75effSDimitry Andric };
5068d75effSDimitry Andric 
5168d75effSDimitry Andric #if defined(__mips64)
5268d75effSDimitry Andric static const uptr kMaxAllowedMallocSize = 2UL << 30;
5368d75effSDimitry Andric 
5468d75effSDimitry Andric struct AP32 {
5568d75effSDimitry Andric   static const uptr kSpaceBeg = 0;
5668d75effSDimitry Andric   static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
5768d75effSDimitry Andric   static const uptr kMetadataSize = sizeof(Metadata);
5868d75effSDimitry Andric   typedef __sanitizer::CompactSizeClassMap SizeClassMap;
5968d75effSDimitry Andric   static const uptr kRegionSizeLog = 20;
6068d75effSDimitry Andric   using AddressSpaceView = LocalAddressSpaceView;
6168d75effSDimitry Andric   typedef MsanMapUnmapCallback MapUnmapCallback;
6268d75effSDimitry Andric   static const uptr kFlags = 0;
6368d75effSDimitry Andric };
6468d75effSDimitry Andric typedef SizeClassAllocator32<AP32> PrimaryAllocator;
6568d75effSDimitry Andric #elif defined(__x86_64__)
66bdd1243dSDimitry Andric #if SANITIZER_NETBSD || SANITIZER_LINUX
6768d75effSDimitry Andric static const uptr kAllocatorSpace = 0x700000000000ULL;
6868d75effSDimitry Andric #else
6968d75effSDimitry Andric static const uptr kAllocatorSpace = 0x600000000000ULL;
7068d75effSDimitry Andric #endif
7168d75effSDimitry Andric static const uptr kMaxAllowedMallocSize = 8UL << 30;
7268d75effSDimitry Andric 
7368d75effSDimitry Andric struct AP64 {  // Allocator64 parameters. Deliberately using a short name.
7468d75effSDimitry Andric   static const uptr kSpaceBeg = kAllocatorSpace;
7568d75effSDimitry Andric   static const uptr kSpaceSize = 0x40000000000;  // 4T.
7668d75effSDimitry Andric   static const uptr kMetadataSize = sizeof(Metadata);
7768d75effSDimitry Andric   typedef DefaultSizeClassMap SizeClassMap;
7868d75effSDimitry Andric   typedef MsanMapUnmapCallback MapUnmapCallback;
7968d75effSDimitry Andric   static const uptr kFlags = 0;
8068d75effSDimitry Andric   using AddressSpaceView = LocalAddressSpaceView;
8168d75effSDimitry Andric };
8268d75effSDimitry Andric 
8368d75effSDimitry Andric typedef SizeClassAllocator64<AP64> PrimaryAllocator;
8468d75effSDimitry Andric 
8506c3fb27SDimitry Andric #elif defined(__loongarch_lp64)
8606c3fb27SDimitry Andric const uptr kAllocatorSpace = 0x700000000000ULL;
8706c3fb27SDimitry Andric const uptr kMaxAllowedMallocSize = 8UL << 30;
8806c3fb27SDimitry Andric 
8906c3fb27SDimitry Andric struct AP64 {  // Allocator64 parameters. Deliberately using a short name.
9006c3fb27SDimitry Andric   static const uptr kSpaceBeg = kAllocatorSpace;
9106c3fb27SDimitry Andric   static const uptr kSpaceSize = 0x40000000000;  // 4T.
9206c3fb27SDimitry Andric   static const uptr kMetadataSize = sizeof(Metadata);
9306c3fb27SDimitry Andric   typedef DefaultSizeClassMap SizeClassMap;
9406c3fb27SDimitry Andric   typedef MsanMapUnmapCallback MapUnmapCallback;
9506c3fb27SDimitry Andric   static const uptr kFlags = 0;
9606c3fb27SDimitry Andric   using AddressSpaceView = LocalAddressSpaceView;
9706c3fb27SDimitry Andric };
9806c3fb27SDimitry Andric 
9906c3fb27SDimitry Andric typedef SizeClassAllocator64<AP64> PrimaryAllocator;
10006c3fb27SDimitry Andric 
10168d75effSDimitry Andric #elif defined(__powerpc64__)
10268d75effSDimitry Andric static const uptr kMaxAllowedMallocSize = 2UL << 30;  // 2G
10368d75effSDimitry Andric 
10468d75effSDimitry Andric struct AP64 {  // Allocator64 parameters. Deliberately using a short name.
10568d75effSDimitry Andric   static const uptr kSpaceBeg = 0x300000000000;
10668d75effSDimitry Andric   static const uptr kSpaceSize = 0x020000000000;  // 2T.
10768d75effSDimitry Andric   static const uptr kMetadataSize = sizeof(Metadata);
10868d75effSDimitry Andric   typedef DefaultSizeClassMap SizeClassMap;
10968d75effSDimitry Andric   typedef MsanMapUnmapCallback MapUnmapCallback;
11068d75effSDimitry Andric   static const uptr kFlags = 0;
11168d75effSDimitry Andric   using AddressSpaceView = LocalAddressSpaceView;
11268d75effSDimitry Andric };
11368d75effSDimitry Andric 
11468d75effSDimitry Andric typedef SizeClassAllocator64<AP64> PrimaryAllocator;
1155ffd83dbSDimitry Andric #elif defined(__s390x__)
1165ffd83dbSDimitry Andric static const uptr kMaxAllowedMallocSize = 2UL << 30;  // 2G
1175ffd83dbSDimitry Andric 
1185ffd83dbSDimitry Andric struct AP64 {  // Allocator64 parameters. Deliberately using a short name.
1195ffd83dbSDimitry Andric   static const uptr kSpaceBeg = 0x440000000000;
1205ffd83dbSDimitry Andric   static const uptr kSpaceSize = 0x020000000000;  // 2T.
1215ffd83dbSDimitry Andric   static const uptr kMetadataSize = sizeof(Metadata);
1225ffd83dbSDimitry Andric   typedef DefaultSizeClassMap SizeClassMap;
1235ffd83dbSDimitry Andric   typedef MsanMapUnmapCallback MapUnmapCallback;
1245ffd83dbSDimitry Andric   static const uptr kFlags = 0;
1255ffd83dbSDimitry Andric   using AddressSpaceView = LocalAddressSpaceView;
1265ffd83dbSDimitry Andric };
1275ffd83dbSDimitry Andric 
1285ffd83dbSDimitry Andric typedef SizeClassAllocator64<AP64> PrimaryAllocator;
12968d75effSDimitry Andric #elif defined(__aarch64__)
130bdd1243dSDimitry Andric static const uptr kMaxAllowedMallocSize = 8UL << 30;
13168d75effSDimitry Andric 
132bdd1243dSDimitry Andric struct AP64 {
133bdd1243dSDimitry Andric   static const uptr kSpaceBeg = 0xE00000000000ULL;
134bdd1243dSDimitry Andric   static const uptr kSpaceSize = 0x40000000000;  // 4T.
13568d75effSDimitry Andric   static const uptr kMetadataSize = sizeof(Metadata);
136bdd1243dSDimitry Andric   typedef DefaultSizeClassMap SizeClassMap;
13768d75effSDimitry Andric   typedef MsanMapUnmapCallback MapUnmapCallback;
13868d75effSDimitry Andric   static const uptr kFlags = 0;
139bdd1243dSDimitry Andric   using AddressSpaceView = LocalAddressSpaceView;
14068d75effSDimitry Andric };
141bdd1243dSDimitry Andric typedef SizeClassAllocator64<AP64> PrimaryAllocator;
14268d75effSDimitry Andric #endif
14368d75effSDimitry Andric typedef CombinedAllocator<PrimaryAllocator> Allocator;
14468d75effSDimitry Andric typedef Allocator::AllocatorCache AllocatorCache;
14568d75effSDimitry Andric 
14668d75effSDimitry Andric static Allocator allocator;
14768d75effSDimitry Andric static AllocatorCache fallback_allocator_cache;
14868d75effSDimitry Andric static StaticSpinMutex fallback_mutex;
14968d75effSDimitry Andric 
150480093f4SDimitry Andric static uptr max_malloc_size;
151480093f4SDimitry Andric 
15268d75effSDimitry Andric void MsanAllocatorInit() {
15368d75effSDimitry Andric   SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
15468d75effSDimitry Andric   allocator.Init(common_flags()->allocator_release_to_os_interval_ms);
155480093f4SDimitry Andric   if (common_flags()->max_allocation_size_mb)
156480093f4SDimitry Andric     max_malloc_size = Min(common_flags()->max_allocation_size_mb << 20,
157480093f4SDimitry Andric                           kMaxAllowedMallocSize);
158480093f4SDimitry Andric   else
159480093f4SDimitry Andric     max_malloc_size = kMaxAllowedMallocSize;
16068d75effSDimitry Andric }
16168d75effSDimitry Andric 
162*5f757f3fSDimitry Andric void LockAllocator() { allocator.ForceLock(); }
163*5f757f3fSDimitry Andric 
164*5f757f3fSDimitry Andric void UnlockAllocator() { allocator.ForceUnlock(); }
165*5f757f3fSDimitry Andric 
16668d75effSDimitry Andric AllocatorCache *GetAllocatorCache(MsanThreadLocalMallocStorage *ms) {
16768d75effSDimitry Andric   CHECK(ms);
16868d75effSDimitry Andric   CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator_cache));
16968d75effSDimitry Andric   return reinterpret_cast<AllocatorCache *>(ms->allocator_cache);
17068d75effSDimitry Andric }
17168d75effSDimitry Andric 
17206c3fb27SDimitry Andric void MsanThreadLocalMallocStorage::Init() {
17306c3fb27SDimitry Andric   allocator.InitCache(GetAllocatorCache(this));
17406c3fb27SDimitry Andric }
17506c3fb27SDimitry Andric 
17668d75effSDimitry Andric void MsanThreadLocalMallocStorage::CommitBack() {
17768d75effSDimitry Andric   allocator.SwallowCache(GetAllocatorCache(this));
17806c3fb27SDimitry Andric   allocator.DestroyCache(GetAllocatorCache(this));
17968d75effSDimitry Andric }
18068d75effSDimitry Andric 
18168d75effSDimitry Andric static void *MsanAllocate(StackTrace *stack, uptr size, uptr alignment,
18268d75effSDimitry Andric                           bool zeroise) {
183480093f4SDimitry Andric   if (size > max_malloc_size) {
18468d75effSDimitry Andric     if (AllocatorMayReturnNull()) {
18568d75effSDimitry Andric       Report("WARNING: MemorySanitizer failed to allocate 0x%zx bytes\n", size);
18668d75effSDimitry Andric       return nullptr;
18768d75effSDimitry Andric     }
188480093f4SDimitry Andric     ReportAllocationSizeTooBig(size, max_malloc_size, stack);
18968d75effSDimitry Andric   }
1900eae32dcSDimitry Andric   if (UNLIKELY(IsRssLimitExceeded())) {
1910eae32dcSDimitry Andric     if (AllocatorMayReturnNull())
1920eae32dcSDimitry Andric       return nullptr;
1930eae32dcSDimitry Andric     ReportRssLimitExceeded(stack);
1940eae32dcSDimitry Andric   }
19568d75effSDimitry Andric   MsanThread *t = GetCurrentThread();
19668d75effSDimitry Andric   void *allocated;
19768d75effSDimitry Andric   if (t) {
19868d75effSDimitry Andric     AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
19968d75effSDimitry Andric     allocated = allocator.Allocate(cache, size, alignment);
20068d75effSDimitry Andric   } else {
20168d75effSDimitry Andric     SpinMutexLock l(&fallback_mutex);
20268d75effSDimitry Andric     AllocatorCache *cache = &fallback_allocator_cache;
20368d75effSDimitry Andric     allocated = allocator.Allocate(cache, size, alignment);
20468d75effSDimitry Andric   }
20568d75effSDimitry Andric   if (UNLIKELY(!allocated)) {
20668d75effSDimitry Andric     SetAllocatorOutOfMemory();
20768d75effSDimitry Andric     if (AllocatorMayReturnNull())
20868d75effSDimitry Andric       return nullptr;
20968d75effSDimitry Andric     ReportOutOfMemory(size, stack);
21068d75effSDimitry Andric   }
21168d75effSDimitry Andric   Metadata *meta =
21268d75effSDimitry Andric       reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
21368d75effSDimitry Andric   meta->requested_size = size;
21468d75effSDimitry Andric   if (zeroise) {
21506c3fb27SDimitry Andric     if (allocator.FromPrimary(allocated))
21668d75effSDimitry Andric       __msan_clear_and_unpoison(allocated, size);
21706c3fb27SDimitry Andric     else
21806c3fb27SDimitry Andric       __msan_unpoison(allocated, size);  // Mem is already zeroed.
21968d75effSDimitry Andric   } else if (flags()->poison_in_malloc) {
22068d75effSDimitry Andric     __msan_poison(allocated, size);
22168d75effSDimitry Andric     if (__msan_get_track_origins()) {
22268d75effSDimitry Andric       stack->tag = StackTrace::TAG_ALLOC;
22368d75effSDimitry Andric       Origin o = Origin::CreateHeapOrigin(stack);
22468d75effSDimitry Andric       __msan_set_origin(allocated, size, o.raw_id());
22568d75effSDimitry Andric     }
22668d75effSDimitry Andric   }
22781ad6265SDimitry Andric   UnpoisonParam(2);
22881ad6265SDimitry Andric   RunMallocHooks(allocated, size);
22968d75effSDimitry Andric   return allocated;
23068d75effSDimitry Andric }
23168d75effSDimitry Andric 
23268d75effSDimitry Andric void MsanDeallocate(StackTrace *stack, void *p) {
23368d75effSDimitry Andric   CHECK(p);
23481ad6265SDimitry Andric   UnpoisonParam(1);
23581ad6265SDimitry Andric   RunFreeHooks(p);
23681ad6265SDimitry Andric 
23768d75effSDimitry Andric   Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(p));
23868d75effSDimitry Andric   uptr size = meta->requested_size;
23968d75effSDimitry Andric   meta->requested_size = 0;
24068d75effSDimitry Andric   // This memory will not be reused by anyone else, so we are free to keep it
24106c3fb27SDimitry Andric   // poisoned. The secondary allocator will unmap and unpoison by
24206c3fb27SDimitry Andric   // MsanMapUnmapCallback, no need to poison it here.
24306c3fb27SDimitry Andric   if (flags()->poison_in_free && allocator.FromPrimary(p)) {
24468d75effSDimitry Andric     __msan_poison(p, size);
24568d75effSDimitry Andric     if (__msan_get_track_origins()) {
24668d75effSDimitry Andric       stack->tag = StackTrace::TAG_DEALLOC;
24768d75effSDimitry Andric       Origin o = Origin::CreateHeapOrigin(stack);
24868d75effSDimitry Andric       __msan_set_origin(p, size, o.raw_id());
24968d75effSDimitry Andric     }
25068d75effSDimitry Andric   }
25168d75effSDimitry Andric   MsanThread *t = GetCurrentThread();
25268d75effSDimitry Andric   if (t) {
25368d75effSDimitry Andric     AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
25468d75effSDimitry Andric     allocator.Deallocate(cache, p);
25568d75effSDimitry Andric   } else {
25668d75effSDimitry Andric     SpinMutexLock l(&fallback_mutex);
25768d75effSDimitry Andric     AllocatorCache *cache = &fallback_allocator_cache;
25868d75effSDimitry Andric     allocator.Deallocate(cache, p);
25968d75effSDimitry Andric   }
26068d75effSDimitry Andric }
26168d75effSDimitry Andric 
262fe6060f1SDimitry Andric static void *MsanReallocate(StackTrace *stack, void *old_p, uptr new_size,
26368d75effSDimitry Andric                             uptr alignment) {
26468d75effSDimitry Andric   Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(old_p));
26568d75effSDimitry Andric   uptr old_size = meta->requested_size;
26668d75effSDimitry Andric   uptr actually_allocated_size = allocator.GetActuallyAllocatedSize(old_p);
26768d75effSDimitry Andric   if (new_size <= actually_allocated_size) {
26868d75effSDimitry Andric     // We are not reallocating here.
26968d75effSDimitry Andric     meta->requested_size = new_size;
27068d75effSDimitry Andric     if (new_size > old_size) {
27168d75effSDimitry Andric       if (flags()->poison_in_malloc) {
27268d75effSDimitry Andric         stack->tag = StackTrace::TAG_ALLOC;
27368d75effSDimitry Andric         PoisonMemory((char *)old_p + old_size, new_size - old_size, stack);
27468d75effSDimitry Andric       }
27568d75effSDimitry Andric     }
27668d75effSDimitry Andric     return old_p;
27768d75effSDimitry Andric   }
27868d75effSDimitry Andric   uptr memcpy_size = Min(new_size, old_size);
27968d75effSDimitry Andric   void *new_p = MsanAllocate(stack, new_size, alignment, false /*zeroise*/);
28068d75effSDimitry Andric   if (new_p) {
28168d75effSDimitry Andric     CopyMemory(new_p, old_p, memcpy_size, stack);
28268d75effSDimitry Andric     MsanDeallocate(stack, old_p);
28368d75effSDimitry Andric   }
28468d75effSDimitry Andric   return new_p;
28568d75effSDimitry Andric }
28668d75effSDimitry Andric 
287fe6060f1SDimitry Andric static void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
28868d75effSDimitry Andric   if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
28968d75effSDimitry Andric     if (AllocatorMayReturnNull())
29068d75effSDimitry Andric       return nullptr;
29168d75effSDimitry Andric     ReportCallocOverflow(nmemb, size, stack);
29268d75effSDimitry Andric   }
29368d75effSDimitry Andric   return MsanAllocate(stack, nmemb * size, sizeof(u64), true);
29468d75effSDimitry Andric }
29568d75effSDimitry Andric 
29606c3fb27SDimitry Andric static const void *AllocationBegin(const void *p) {
29706c3fb27SDimitry Andric   if (!p)
29806c3fb27SDimitry Andric     return nullptr;
29906c3fb27SDimitry Andric   void *beg = allocator.GetBlockBegin(p);
30006c3fb27SDimitry Andric   if (!beg)
30106c3fb27SDimitry Andric     return nullptr;
30206c3fb27SDimitry Andric   Metadata *b = (Metadata *)allocator.GetMetaData(beg);
30306c3fb27SDimitry Andric   if (!b)
30406c3fb27SDimitry Andric     return nullptr;
30506c3fb27SDimitry Andric   if (b->requested_size == 0)
30606c3fb27SDimitry Andric     return nullptr;
30706c3fb27SDimitry Andric 
30806c3fb27SDimitry Andric   return (const void *)beg;
30906c3fb27SDimitry Andric }
31006c3fb27SDimitry Andric 
31168d75effSDimitry Andric static uptr AllocationSize(const void *p) {
31268d75effSDimitry Andric   if (!p) return 0;
31368d75effSDimitry Andric   const void *beg = allocator.GetBlockBegin(p);
31468d75effSDimitry Andric   if (beg != p) return 0;
31568d75effSDimitry Andric   Metadata *b = (Metadata *)allocator.GetMetaData(p);
31668d75effSDimitry Andric   return b->requested_size;
31768d75effSDimitry Andric }
31868d75effSDimitry Andric 
31906c3fb27SDimitry Andric static uptr AllocationSizeFast(const void *p) {
32006c3fb27SDimitry Andric   return reinterpret_cast<Metadata *>(allocator.GetMetaData(p))->requested_size;
32106c3fb27SDimitry Andric }
32206c3fb27SDimitry Andric 
32368d75effSDimitry Andric void *msan_malloc(uptr size, StackTrace *stack) {
32468d75effSDimitry Andric   return SetErrnoOnNull(MsanAllocate(stack, size, sizeof(u64), false));
32568d75effSDimitry Andric }
32668d75effSDimitry Andric 
32768d75effSDimitry Andric void *msan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
32868d75effSDimitry Andric   return SetErrnoOnNull(MsanCalloc(stack, nmemb, size));
32968d75effSDimitry Andric }
33068d75effSDimitry Andric 
33168d75effSDimitry Andric void *msan_realloc(void *ptr, uptr size, StackTrace *stack) {
33268d75effSDimitry Andric   if (!ptr)
33368d75effSDimitry Andric     return SetErrnoOnNull(MsanAllocate(stack, size, sizeof(u64), false));
33468d75effSDimitry Andric   if (size == 0) {
33568d75effSDimitry Andric     MsanDeallocate(stack, ptr);
33668d75effSDimitry Andric     return nullptr;
33768d75effSDimitry Andric   }
33868d75effSDimitry Andric   return SetErrnoOnNull(MsanReallocate(stack, ptr, size, sizeof(u64)));
33968d75effSDimitry Andric }
34068d75effSDimitry Andric 
34168d75effSDimitry Andric void *msan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack) {
34268d75effSDimitry Andric   if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
34368d75effSDimitry Andric     errno = errno_ENOMEM;
34468d75effSDimitry Andric     if (AllocatorMayReturnNull())
34568d75effSDimitry Andric       return nullptr;
34668d75effSDimitry Andric     ReportReallocArrayOverflow(nmemb, size, stack);
34768d75effSDimitry Andric   }
34868d75effSDimitry Andric   return msan_realloc(ptr, nmemb * size, stack);
34968d75effSDimitry Andric }
35068d75effSDimitry Andric 
35168d75effSDimitry Andric void *msan_valloc(uptr size, StackTrace *stack) {
35268d75effSDimitry Andric   return SetErrnoOnNull(MsanAllocate(stack, size, GetPageSizeCached(), false));
35368d75effSDimitry Andric }
35468d75effSDimitry Andric 
35568d75effSDimitry Andric void *msan_pvalloc(uptr size, StackTrace *stack) {
35668d75effSDimitry Andric   uptr PageSize = GetPageSizeCached();
35768d75effSDimitry Andric   if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) {
35868d75effSDimitry Andric     errno = errno_ENOMEM;
35968d75effSDimitry Andric     if (AllocatorMayReturnNull())
36068d75effSDimitry Andric       return nullptr;
36168d75effSDimitry Andric     ReportPvallocOverflow(size, stack);
36268d75effSDimitry Andric   }
36368d75effSDimitry Andric   // pvalloc(0) should allocate one page.
36468d75effSDimitry Andric   size = size ? RoundUpTo(size, PageSize) : PageSize;
36568d75effSDimitry Andric   return SetErrnoOnNull(MsanAllocate(stack, size, PageSize, false));
36668d75effSDimitry Andric }
36768d75effSDimitry Andric 
36868d75effSDimitry Andric void *msan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) {
36968d75effSDimitry Andric   if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) {
37068d75effSDimitry Andric     errno = errno_EINVAL;
37168d75effSDimitry Andric     if (AllocatorMayReturnNull())
37268d75effSDimitry Andric       return nullptr;
37368d75effSDimitry Andric     ReportInvalidAlignedAllocAlignment(size, alignment, stack);
37468d75effSDimitry Andric   }
37568d75effSDimitry Andric   return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false));
37668d75effSDimitry Andric }
37768d75effSDimitry Andric 
37868d75effSDimitry Andric void *msan_memalign(uptr alignment, uptr size, StackTrace *stack) {
37968d75effSDimitry Andric   if (UNLIKELY(!IsPowerOfTwo(alignment))) {
38068d75effSDimitry Andric     errno = errno_EINVAL;
38168d75effSDimitry Andric     if (AllocatorMayReturnNull())
38268d75effSDimitry Andric       return nullptr;
38368d75effSDimitry Andric     ReportInvalidAllocationAlignment(alignment, stack);
38468d75effSDimitry Andric   }
38568d75effSDimitry Andric   return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false));
38668d75effSDimitry Andric }
38768d75effSDimitry Andric 
38868d75effSDimitry Andric int msan_posix_memalign(void **memptr, uptr alignment, uptr size,
38968d75effSDimitry Andric                         StackTrace *stack) {
39068d75effSDimitry Andric   if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) {
39168d75effSDimitry Andric     if (AllocatorMayReturnNull())
39268d75effSDimitry Andric       return errno_EINVAL;
39368d75effSDimitry Andric     ReportInvalidPosixMemalignAlignment(alignment, stack);
39468d75effSDimitry Andric   }
39568d75effSDimitry Andric   void *ptr = MsanAllocate(stack, size, alignment, false);
39668d75effSDimitry Andric   if (UNLIKELY(!ptr))
39768d75effSDimitry Andric     // OOM error is already taken care of by MsanAllocate.
39868d75effSDimitry Andric     return errno_ENOMEM;
39968d75effSDimitry Andric   CHECK(IsAligned((uptr)ptr, alignment));
40068d75effSDimitry Andric   *memptr = ptr;
40168d75effSDimitry Andric   return 0;
40268d75effSDimitry Andric }
40368d75effSDimitry Andric 
40468d75effSDimitry Andric } // namespace __msan
40568d75effSDimitry Andric 
40668d75effSDimitry Andric using namespace __msan;
40768d75effSDimitry Andric 
40868d75effSDimitry Andric uptr __sanitizer_get_current_allocated_bytes() {
40968d75effSDimitry Andric   uptr stats[AllocatorStatCount];
41068d75effSDimitry Andric   allocator.GetStats(stats);
41168d75effSDimitry Andric   return stats[AllocatorStatAllocated];
41268d75effSDimitry Andric }
41368d75effSDimitry Andric 
41468d75effSDimitry Andric uptr __sanitizer_get_heap_size() {
41568d75effSDimitry Andric   uptr stats[AllocatorStatCount];
41668d75effSDimitry Andric   allocator.GetStats(stats);
41768d75effSDimitry Andric   return stats[AllocatorStatMapped];
41868d75effSDimitry Andric }
41968d75effSDimitry Andric 
42068d75effSDimitry Andric uptr __sanitizer_get_free_bytes() { return 1; }
42168d75effSDimitry Andric 
42268d75effSDimitry Andric uptr __sanitizer_get_unmapped_bytes() { return 1; }
42368d75effSDimitry Andric 
42468d75effSDimitry Andric uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
42568d75effSDimitry Andric 
42668d75effSDimitry Andric int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; }
42768d75effSDimitry Andric 
42806c3fb27SDimitry Andric const void *__sanitizer_get_allocated_begin(const void *p) {
42906c3fb27SDimitry Andric   return AllocationBegin(p);
43006c3fb27SDimitry Andric }
43106c3fb27SDimitry Andric 
43268d75effSDimitry Andric uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); }
43306c3fb27SDimitry Andric 
43406c3fb27SDimitry Andric uptr __sanitizer_get_allocated_size_fast(const void *p) {
43506c3fb27SDimitry Andric   DCHECK_EQ(p, __sanitizer_get_allocated_begin(p));
43606c3fb27SDimitry Andric   uptr ret = AllocationSizeFast(p);
43706c3fb27SDimitry Andric   DCHECK_EQ(ret, __sanitizer_get_allocated_size(p));
43806c3fb27SDimitry Andric   return ret;
43906c3fb27SDimitry Andric }
44006c3fb27SDimitry Andric 
44106c3fb27SDimitry Andric void __sanitizer_purge_allocator() { allocator.ForceReleaseToOS(); }
442