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 51439352acSDimitry Andric // Note: to ensure that the allocator is compatible with the application memory 52439352acSDimitry Andric // layout (especially with high-entropy ASLR), kSpaceBeg and kSpaceSize must be 53439352acSDimitry Andric // duplicated as MappingDesc::ALLOCATOR in msan.h. 5468d75effSDimitry Andric #if defined(__mips64) 5568d75effSDimitry Andric static const uptr kMaxAllowedMallocSize = 2UL << 30; 5668d75effSDimitry Andric 5768d75effSDimitry Andric struct AP32 { 5868d75effSDimitry Andric static const uptr kSpaceBeg = 0; 5968d75effSDimitry Andric static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; 6068d75effSDimitry Andric static const uptr kMetadataSize = sizeof(Metadata); 6168d75effSDimitry Andric typedef __sanitizer::CompactSizeClassMap SizeClassMap; 6268d75effSDimitry Andric static const uptr kRegionSizeLog = 20; 6368d75effSDimitry Andric using AddressSpaceView = LocalAddressSpaceView; 6468d75effSDimitry Andric typedef MsanMapUnmapCallback MapUnmapCallback; 6568d75effSDimitry Andric static const uptr kFlags = 0; 6668d75effSDimitry Andric }; 6768d75effSDimitry Andric typedef SizeClassAllocator32<AP32> PrimaryAllocator; 6868d75effSDimitry Andric #elif defined(__x86_64__) 69bdd1243dSDimitry Andric #if SANITIZER_NETBSD || SANITIZER_LINUX 7068d75effSDimitry Andric static const uptr kAllocatorSpace = 0x700000000000ULL; 7168d75effSDimitry Andric #else 7268d75effSDimitry Andric static const uptr kAllocatorSpace = 0x600000000000ULL; 7368d75effSDimitry Andric #endif 74*0fca6ea1SDimitry Andric static const uptr kMaxAllowedMallocSize = 1ULL << 40; 7568d75effSDimitry Andric 7668d75effSDimitry Andric struct AP64 { // Allocator64 parameters. Deliberately using a short name. 7768d75effSDimitry Andric static const uptr kSpaceBeg = kAllocatorSpace; 7868d75effSDimitry Andric static const uptr kSpaceSize = 0x40000000000; // 4T. 7968d75effSDimitry Andric static const uptr kMetadataSize = sizeof(Metadata); 8068d75effSDimitry Andric typedef DefaultSizeClassMap SizeClassMap; 8168d75effSDimitry Andric typedef MsanMapUnmapCallback MapUnmapCallback; 8268d75effSDimitry Andric static const uptr kFlags = 0; 8368d75effSDimitry Andric using AddressSpaceView = LocalAddressSpaceView; 8468d75effSDimitry Andric }; 8568d75effSDimitry Andric 8668d75effSDimitry Andric typedef SizeClassAllocator64<AP64> PrimaryAllocator; 8768d75effSDimitry Andric 8806c3fb27SDimitry Andric #elif defined(__loongarch_lp64) 8906c3fb27SDimitry Andric const uptr kAllocatorSpace = 0x700000000000ULL; 9006c3fb27SDimitry Andric const uptr kMaxAllowedMallocSize = 8UL << 30; 9106c3fb27SDimitry Andric 9206c3fb27SDimitry Andric struct AP64 { // Allocator64 parameters. Deliberately using a short name. 9306c3fb27SDimitry Andric static const uptr kSpaceBeg = kAllocatorSpace; 9406c3fb27SDimitry Andric static const uptr kSpaceSize = 0x40000000000; // 4T. 9506c3fb27SDimitry Andric static const uptr kMetadataSize = sizeof(Metadata); 9606c3fb27SDimitry Andric typedef DefaultSizeClassMap SizeClassMap; 9706c3fb27SDimitry Andric typedef MsanMapUnmapCallback MapUnmapCallback; 9806c3fb27SDimitry Andric static const uptr kFlags = 0; 9906c3fb27SDimitry Andric using AddressSpaceView = LocalAddressSpaceView; 10006c3fb27SDimitry Andric }; 10106c3fb27SDimitry Andric 10206c3fb27SDimitry Andric typedef SizeClassAllocator64<AP64> PrimaryAllocator; 10306c3fb27SDimitry Andric 10468d75effSDimitry Andric #elif defined(__powerpc64__) 10568d75effSDimitry Andric static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G 10668d75effSDimitry Andric 10768d75effSDimitry Andric struct AP64 { // Allocator64 parameters. Deliberately using a short name. 10868d75effSDimitry Andric static const uptr kSpaceBeg = 0x300000000000; 10968d75effSDimitry Andric static const uptr kSpaceSize = 0x020000000000; // 2T. 11068d75effSDimitry Andric static const uptr kMetadataSize = sizeof(Metadata); 11168d75effSDimitry Andric typedef DefaultSizeClassMap SizeClassMap; 11268d75effSDimitry Andric typedef MsanMapUnmapCallback MapUnmapCallback; 11368d75effSDimitry Andric static const uptr kFlags = 0; 11468d75effSDimitry Andric using AddressSpaceView = LocalAddressSpaceView; 11568d75effSDimitry Andric }; 11668d75effSDimitry Andric 11768d75effSDimitry Andric typedef SizeClassAllocator64<AP64> PrimaryAllocator; 1185ffd83dbSDimitry Andric #elif defined(__s390x__) 1195ffd83dbSDimitry Andric static const uptr kMaxAllowedMallocSize = 2UL << 30; // 2G 1205ffd83dbSDimitry Andric 1215ffd83dbSDimitry Andric struct AP64 { // Allocator64 parameters. Deliberately using a short name. 1225ffd83dbSDimitry Andric static const uptr kSpaceBeg = 0x440000000000; 1235ffd83dbSDimitry Andric static const uptr kSpaceSize = 0x020000000000; // 2T. 1245ffd83dbSDimitry Andric static const uptr kMetadataSize = sizeof(Metadata); 1255ffd83dbSDimitry Andric typedef DefaultSizeClassMap SizeClassMap; 1265ffd83dbSDimitry Andric typedef MsanMapUnmapCallback MapUnmapCallback; 1275ffd83dbSDimitry Andric static const uptr kFlags = 0; 1285ffd83dbSDimitry Andric using AddressSpaceView = LocalAddressSpaceView; 1295ffd83dbSDimitry Andric }; 1305ffd83dbSDimitry Andric 1315ffd83dbSDimitry Andric typedef SizeClassAllocator64<AP64> PrimaryAllocator; 13268d75effSDimitry Andric #elif defined(__aarch64__) 133bdd1243dSDimitry Andric static const uptr kMaxAllowedMallocSize = 8UL << 30; 13468d75effSDimitry Andric 135bdd1243dSDimitry Andric struct AP64 { 136bdd1243dSDimitry Andric static const uptr kSpaceBeg = 0xE00000000000ULL; 137bdd1243dSDimitry Andric static const uptr kSpaceSize = 0x40000000000; // 4T. 13868d75effSDimitry Andric static const uptr kMetadataSize = sizeof(Metadata); 139bdd1243dSDimitry Andric typedef DefaultSizeClassMap SizeClassMap; 14068d75effSDimitry Andric typedef MsanMapUnmapCallback MapUnmapCallback; 14168d75effSDimitry Andric static const uptr kFlags = 0; 142bdd1243dSDimitry Andric using AddressSpaceView = LocalAddressSpaceView; 14368d75effSDimitry Andric }; 144bdd1243dSDimitry Andric typedef SizeClassAllocator64<AP64> PrimaryAllocator; 14568d75effSDimitry Andric #endif 14668d75effSDimitry Andric typedef CombinedAllocator<PrimaryAllocator> Allocator; 14768d75effSDimitry Andric typedef Allocator::AllocatorCache AllocatorCache; 14868d75effSDimitry Andric 14968d75effSDimitry Andric static Allocator allocator; 15068d75effSDimitry Andric static AllocatorCache fallback_allocator_cache; 15168d75effSDimitry Andric static StaticSpinMutex fallback_mutex; 15268d75effSDimitry Andric 153480093f4SDimitry Andric static uptr max_malloc_size; 154480093f4SDimitry Andric 15568d75effSDimitry Andric void MsanAllocatorInit() { 15668d75effSDimitry Andric SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); 15768d75effSDimitry Andric allocator.Init(common_flags()->allocator_release_to_os_interval_ms); 158480093f4SDimitry Andric if (common_flags()->max_allocation_size_mb) 159480093f4SDimitry Andric max_malloc_size = Min(common_flags()->max_allocation_size_mb << 20, 160480093f4SDimitry Andric kMaxAllowedMallocSize); 161480093f4SDimitry Andric else 162480093f4SDimitry Andric max_malloc_size = kMaxAllowedMallocSize; 16368d75effSDimitry Andric } 16468d75effSDimitry Andric 1655f757f3fSDimitry Andric void LockAllocator() { allocator.ForceLock(); } 1665f757f3fSDimitry Andric 1675f757f3fSDimitry Andric void UnlockAllocator() { allocator.ForceUnlock(); } 1685f757f3fSDimitry Andric 16968d75effSDimitry Andric AllocatorCache *GetAllocatorCache(MsanThreadLocalMallocStorage *ms) { 17068d75effSDimitry Andric CHECK(ms); 17168d75effSDimitry Andric CHECK_LE(sizeof(AllocatorCache), sizeof(ms->allocator_cache)); 17268d75effSDimitry Andric return reinterpret_cast<AllocatorCache *>(ms->allocator_cache); 17368d75effSDimitry Andric } 17468d75effSDimitry Andric 17506c3fb27SDimitry Andric void MsanThreadLocalMallocStorage::Init() { 17606c3fb27SDimitry Andric allocator.InitCache(GetAllocatorCache(this)); 17706c3fb27SDimitry Andric } 17806c3fb27SDimitry Andric 17968d75effSDimitry Andric void MsanThreadLocalMallocStorage::CommitBack() { 18068d75effSDimitry Andric allocator.SwallowCache(GetAllocatorCache(this)); 18106c3fb27SDimitry Andric allocator.DestroyCache(GetAllocatorCache(this)); 18268d75effSDimitry Andric } 18368d75effSDimitry Andric 1841db9f3b2SDimitry Andric static void *MsanAllocate(BufferedStackTrace *stack, uptr size, uptr alignment, 18568d75effSDimitry Andric bool zeroise) { 1861db9f3b2SDimitry Andric if (UNLIKELY(size > max_malloc_size)) { 18768d75effSDimitry Andric if (AllocatorMayReturnNull()) { 18868d75effSDimitry Andric Report("WARNING: MemorySanitizer failed to allocate 0x%zx bytes\n", size); 18968d75effSDimitry Andric return nullptr; 19068d75effSDimitry Andric } 1911db9f3b2SDimitry Andric GET_FATAL_STACK_TRACE_IF_EMPTY(stack); 192480093f4SDimitry Andric ReportAllocationSizeTooBig(size, max_malloc_size, stack); 19368d75effSDimitry Andric } 1940eae32dcSDimitry Andric if (UNLIKELY(IsRssLimitExceeded())) { 1950eae32dcSDimitry Andric if (AllocatorMayReturnNull()) 1960eae32dcSDimitry Andric return nullptr; 1971db9f3b2SDimitry Andric GET_FATAL_STACK_TRACE_IF_EMPTY(stack); 1980eae32dcSDimitry Andric ReportRssLimitExceeded(stack); 1990eae32dcSDimitry Andric } 20068d75effSDimitry Andric MsanThread *t = GetCurrentThread(); 20168d75effSDimitry Andric void *allocated; 20268d75effSDimitry Andric if (t) { 20368d75effSDimitry Andric AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage()); 20468d75effSDimitry Andric allocated = allocator.Allocate(cache, size, alignment); 20568d75effSDimitry Andric } else { 20668d75effSDimitry Andric SpinMutexLock l(&fallback_mutex); 20768d75effSDimitry Andric AllocatorCache *cache = &fallback_allocator_cache; 20868d75effSDimitry Andric allocated = allocator.Allocate(cache, size, alignment); 20968d75effSDimitry Andric } 21068d75effSDimitry Andric if (UNLIKELY(!allocated)) { 21168d75effSDimitry Andric SetAllocatorOutOfMemory(); 21268d75effSDimitry Andric if (AllocatorMayReturnNull()) 21368d75effSDimitry Andric return nullptr; 2141db9f3b2SDimitry Andric GET_FATAL_STACK_TRACE_IF_EMPTY(stack); 21568d75effSDimitry Andric ReportOutOfMemory(size, stack); 21668d75effSDimitry Andric } 21768d75effSDimitry Andric Metadata *meta = 21868d75effSDimitry Andric reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated)); 21968d75effSDimitry Andric meta->requested_size = size; 22068d75effSDimitry Andric if (zeroise) { 22106c3fb27SDimitry Andric if (allocator.FromPrimary(allocated)) 22268d75effSDimitry Andric __msan_clear_and_unpoison(allocated, size); 22306c3fb27SDimitry Andric else 22406c3fb27SDimitry Andric __msan_unpoison(allocated, size); // Mem is already zeroed. 22568d75effSDimitry Andric } else if (flags()->poison_in_malloc) { 22668d75effSDimitry Andric __msan_poison(allocated, size); 22768d75effSDimitry Andric if (__msan_get_track_origins()) { 22868d75effSDimitry Andric stack->tag = StackTrace::TAG_ALLOC; 22968d75effSDimitry Andric Origin o = Origin::CreateHeapOrigin(stack); 23068d75effSDimitry Andric __msan_set_origin(allocated, size, o.raw_id()); 23168d75effSDimitry Andric } 23268d75effSDimitry Andric } 23381ad6265SDimitry Andric UnpoisonParam(2); 23481ad6265SDimitry Andric RunMallocHooks(allocated, size); 23568d75effSDimitry Andric return allocated; 23668d75effSDimitry Andric } 23768d75effSDimitry Andric 2381db9f3b2SDimitry Andric void MsanDeallocate(BufferedStackTrace *stack, void *p) { 23968d75effSDimitry Andric CHECK(p); 24081ad6265SDimitry Andric UnpoisonParam(1); 24181ad6265SDimitry Andric RunFreeHooks(p); 24281ad6265SDimitry Andric 24368d75effSDimitry Andric Metadata *meta = reinterpret_cast<Metadata *>(allocator.GetMetaData(p)); 24468d75effSDimitry Andric uptr size = meta->requested_size; 24568d75effSDimitry Andric meta->requested_size = 0; 24668d75effSDimitry Andric // This memory will not be reused by anyone else, so we are free to keep it 24706c3fb27SDimitry Andric // poisoned. The secondary allocator will unmap and unpoison by 24806c3fb27SDimitry Andric // MsanMapUnmapCallback, no need to poison it here. 24906c3fb27SDimitry Andric if (flags()->poison_in_free && allocator.FromPrimary(p)) { 25068d75effSDimitry Andric __msan_poison(p, size); 25168d75effSDimitry Andric if (__msan_get_track_origins()) { 25268d75effSDimitry Andric stack->tag = StackTrace::TAG_DEALLOC; 25368d75effSDimitry Andric Origin o = Origin::CreateHeapOrigin(stack); 25468d75effSDimitry Andric __msan_set_origin(p, size, o.raw_id()); 25568d75effSDimitry Andric } 25668d75effSDimitry Andric } 25768d75effSDimitry Andric MsanThread *t = GetCurrentThread(); 25868d75effSDimitry Andric if (t) { 25968d75effSDimitry Andric AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage()); 26068d75effSDimitry Andric allocator.Deallocate(cache, p); 26168d75effSDimitry Andric } else { 26268d75effSDimitry Andric SpinMutexLock l(&fallback_mutex); 26368d75effSDimitry Andric AllocatorCache *cache = &fallback_allocator_cache; 26468d75effSDimitry Andric allocator.Deallocate(cache, p); 26568d75effSDimitry Andric } 26668d75effSDimitry Andric } 26768d75effSDimitry Andric 2681db9f3b2SDimitry Andric static void *MsanReallocate(BufferedStackTrace *stack, void *old_p, 2691db9f3b2SDimitry Andric uptr new_size, uptr alignment) { 27068d75effSDimitry Andric Metadata *meta = reinterpret_cast<Metadata*>(allocator.GetMetaData(old_p)); 27168d75effSDimitry Andric uptr old_size = meta->requested_size; 27268d75effSDimitry Andric uptr actually_allocated_size = allocator.GetActuallyAllocatedSize(old_p); 27368d75effSDimitry Andric if (new_size <= actually_allocated_size) { 27468d75effSDimitry Andric // We are not reallocating here. 27568d75effSDimitry Andric meta->requested_size = new_size; 27668d75effSDimitry Andric if (new_size > old_size) { 27768d75effSDimitry Andric if (flags()->poison_in_malloc) { 27868d75effSDimitry Andric stack->tag = StackTrace::TAG_ALLOC; 27968d75effSDimitry Andric PoisonMemory((char *)old_p + old_size, new_size - old_size, stack); 28068d75effSDimitry Andric } 28168d75effSDimitry Andric } 28268d75effSDimitry Andric return old_p; 28368d75effSDimitry Andric } 28468d75effSDimitry Andric uptr memcpy_size = Min(new_size, old_size); 28568d75effSDimitry Andric void *new_p = MsanAllocate(stack, new_size, alignment, false /*zeroise*/); 28668d75effSDimitry Andric if (new_p) { 28768d75effSDimitry Andric CopyMemory(new_p, old_p, memcpy_size, stack); 28868d75effSDimitry Andric MsanDeallocate(stack, old_p); 28968d75effSDimitry Andric } 29068d75effSDimitry Andric return new_p; 29168d75effSDimitry Andric } 29268d75effSDimitry Andric 2931db9f3b2SDimitry Andric static void *MsanCalloc(BufferedStackTrace *stack, uptr nmemb, uptr size) { 29468d75effSDimitry Andric if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { 29568d75effSDimitry Andric if (AllocatorMayReturnNull()) 29668d75effSDimitry Andric return nullptr; 2971db9f3b2SDimitry Andric GET_FATAL_STACK_TRACE_IF_EMPTY(stack); 29868d75effSDimitry Andric ReportCallocOverflow(nmemb, size, stack); 29968d75effSDimitry Andric } 30068d75effSDimitry Andric return MsanAllocate(stack, nmemb * size, sizeof(u64), true); 30168d75effSDimitry Andric } 30268d75effSDimitry Andric 30306c3fb27SDimitry Andric static const void *AllocationBegin(const void *p) { 30406c3fb27SDimitry Andric if (!p) 30506c3fb27SDimitry Andric return nullptr; 30606c3fb27SDimitry Andric void *beg = allocator.GetBlockBegin(p); 30706c3fb27SDimitry Andric if (!beg) 30806c3fb27SDimitry Andric return nullptr; 30906c3fb27SDimitry Andric Metadata *b = (Metadata *)allocator.GetMetaData(beg); 31006c3fb27SDimitry Andric if (!b) 31106c3fb27SDimitry Andric return nullptr; 31206c3fb27SDimitry Andric if (b->requested_size == 0) 31306c3fb27SDimitry Andric return nullptr; 31406c3fb27SDimitry Andric 31506c3fb27SDimitry Andric return (const void *)beg; 31606c3fb27SDimitry Andric } 31706c3fb27SDimitry Andric 31868d75effSDimitry Andric static uptr AllocationSize(const void *p) { 31968d75effSDimitry Andric if (!p) return 0; 32068d75effSDimitry Andric const void *beg = allocator.GetBlockBegin(p); 32168d75effSDimitry Andric if (beg != p) return 0; 32268d75effSDimitry Andric Metadata *b = (Metadata *)allocator.GetMetaData(p); 32368d75effSDimitry Andric return b->requested_size; 32468d75effSDimitry Andric } 32568d75effSDimitry Andric 32606c3fb27SDimitry Andric static uptr AllocationSizeFast(const void *p) { 32706c3fb27SDimitry Andric return reinterpret_cast<Metadata *>(allocator.GetMetaData(p))->requested_size; 32806c3fb27SDimitry Andric } 32906c3fb27SDimitry Andric 3301db9f3b2SDimitry Andric void *msan_malloc(uptr size, BufferedStackTrace *stack) { 33168d75effSDimitry Andric return SetErrnoOnNull(MsanAllocate(stack, size, sizeof(u64), false)); 33268d75effSDimitry Andric } 33368d75effSDimitry Andric 3341db9f3b2SDimitry Andric void *msan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { 33568d75effSDimitry Andric return SetErrnoOnNull(MsanCalloc(stack, nmemb, size)); 33668d75effSDimitry Andric } 33768d75effSDimitry Andric 3381db9f3b2SDimitry Andric void *msan_realloc(void *ptr, uptr size, BufferedStackTrace *stack) { 33968d75effSDimitry Andric if (!ptr) 34068d75effSDimitry Andric return SetErrnoOnNull(MsanAllocate(stack, size, sizeof(u64), false)); 34168d75effSDimitry Andric if (size == 0) { 34268d75effSDimitry Andric MsanDeallocate(stack, ptr); 34368d75effSDimitry Andric return nullptr; 34468d75effSDimitry Andric } 34568d75effSDimitry Andric return SetErrnoOnNull(MsanReallocate(stack, ptr, size, sizeof(u64))); 34668d75effSDimitry Andric } 34768d75effSDimitry Andric 3481db9f3b2SDimitry Andric void *msan_reallocarray(void *ptr, uptr nmemb, uptr size, 3491db9f3b2SDimitry Andric BufferedStackTrace *stack) { 35068d75effSDimitry Andric if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { 35168d75effSDimitry Andric errno = errno_ENOMEM; 35268d75effSDimitry Andric if (AllocatorMayReturnNull()) 35368d75effSDimitry Andric return nullptr; 3541db9f3b2SDimitry Andric GET_FATAL_STACK_TRACE_IF_EMPTY(stack); 35568d75effSDimitry Andric ReportReallocArrayOverflow(nmemb, size, stack); 35668d75effSDimitry Andric } 35768d75effSDimitry Andric return msan_realloc(ptr, nmemb * size, stack); 35868d75effSDimitry Andric } 35968d75effSDimitry Andric 3601db9f3b2SDimitry Andric void *msan_valloc(uptr size, BufferedStackTrace *stack) { 36168d75effSDimitry Andric return SetErrnoOnNull(MsanAllocate(stack, size, GetPageSizeCached(), false)); 36268d75effSDimitry Andric } 36368d75effSDimitry Andric 3641db9f3b2SDimitry Andric void *msan_pvalloc(uptr size, BufferedStackTrace *stack) { 36568d75effSDimitry Andric uptr PageSize = GetPageSizeCached(); 36668d75effSDimitry Andric if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) { 36768d75effSDimitry Andric errno = errno_ENOMEM; 36868d75effSDimitry Andric if (AllocatorMayReturnNull()) 36968d75effSDimitry Andric return nullptr; 3701db9f3b2SDimitry Andric GET_FATAL_STACK_TRACE_IF_EMPTY(stack); 37168d75effSDimitry Andric ReportPvallocOverflow(size, stack); 37268d75effSDimitry Andric } 37368d75effSDimitry Andric // pvalloc(0) should allocate one page. 37468d75effSDimitry Andric size = size ? RoundUpTo(size, PageSize) : PageSize; 37568d75effSDimitry Andric return SetErrnoOnNull(MsanAllocate(stack, size, PageSize, false)); 37668d75effSDimitry Andric } 37768d75effSDimitry Andric 3781db9f3b2SDimitry Andric void *msan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack) { 37968d75effSDimitry Andric if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) { 38068d75effSDimitry Andric errno = errno_EINVAL; 38168d75effSDimitry Andric if (AllocatorMayReturnNull()) 38268d75effSDimitry Andric return nullptr; 3831db9f3b2SDimitry Andric GET_FATAL_STACK_TRACE_IF_EMPTY(stack); 38468d75effSDimitry Andric ReportInvalidAlignedAllocAlignment(size, alignment, stack); 38568d75effSDimitry Andric } 38668d75effSDimitry Andric return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false)); 38768d75effSDimitry Andric } 38868d75effSDimitry Andric 3891db9f3b2SDimitry Andric void *msan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack) { 39068d75effSDimitry Andric if (UNLIKELY(!IsPowerOfTwo(alignment))) { 39168d75effSDimitry Andric errno = errno_EINVAL; 39268d75effSDimitry Andric if (AllocatorMayReturnNull()) 39368d75effSDimitry Andric return nullptr; 3941db9f3b2SDimitry Andric GET_FATAL_STACK_TRACE_IF_EMPTY(stack); 39568d75effSDimitry Andric ReportInvalidAllocationAlignment(alignment, stack); 39668d75effSDimitry Andric } 39768d75effSDimitry Andric return SetErrnoOnNull(MsanAllocate(stack, size, alignment, false)); 39868d75effSDimitry Andric } 39968d75effSDimitry Andric 40068d75effSDimitry Andric int msan_posix_memalign(void **memptr, uptr alignment, uptr size, 4011db9f3b2SDimitry Andric BufferedStackTrace *stack) { 40268d75effSDimitry Andric if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { 40368d75effSDimitry Andric if (AllocatorMayReturnNull()) 40468d75effSDimitry Andric return errno_EINVAL; 4051db9f3b2SDimitry Andric GET_FATAL_STACK_TRACE_IF_EMPTY(stack); 40668d75effSDimitry Andric ReportInvalidPosixMemalignAlignment(alignment, stack); 40768d75effSDimitry Andric } 40868d75effSDimitry Andric void *ptr = MsanAllocate(stack, size, alignment, false); 40968d75effSDimitry Andric if (UNLIKELY(!ptr)) 41068d75effSDimitry Andric // OOM error is already taken care of by MsanAllocate. 41168d75effSDimitry Andric return errno_ENOMEM; 41268d75effSDimitry Andric CHECK(IsAligned((uptr)ptr, alignment)); 41368d75effSDimitry Andric *memptr = ptr; 41468d75effSDimitry Andric return 0; 41568d75effSDimitry Andric } 41668d75effSDimitry Andric 41768d75effSDimitry Andric } // namespace __msan 41868d75effSDimitry Andric 41968d75effSDimitry Andric using namespace __msan; 42068d75effSDimitry Andric 42168d75effSDimitry Andric uptr __sanitizer_get_current_allocated_bytes() { 42268d75effSDimitry Andric uptr stats[AllocatorStatCount]; 42368d75effSDimitry Andric allocator.GetStats(stats); 42468d75effSDimitry Andric return stats[AllocatorStatAllocated]; 42568d75effSDimitry Andric } 42668d75effSDimitry Andric 42768d75effSDimitry Andric uptr __sanitizer_get_heap_size() { 42868d75effSDimitry Andric uptr stats[AllocatorStatCount]; 42968d75effSDimitry Andric allocator.GetStats(stats); 43068d75effSDimitry Andric return stats[AllocatorStatMapped]; 43168d75effSDimitry Andric } 43268d75effSDimitry Andric 43368d75effSDimitry Andric uptr __sanitizer_get_free_bytes() { return 1; } 43468d75effSDimitry Andric 43568d75effSDimitry Andric uptr __sanitizer_get_unmapped_bytes() { return 1; } 43668d75effSDimitry Andric 43768d75effSDimitry Andric uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; } 43868d75effSDimitry Andric 43968d75effSDimitry Andric int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; } 44068d75effSDimitry Andric 44106c3fb27SDimitry Andric const void *__sanitizer_get_allocated_begin(const void *p) { 44206c3fb27SDimitry Andric return AllocationBegin(p); 44306c3fb27SDimitry Andric } 44406c3fb27SDimitry Andric 44568d75effSDimitry Andric uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); } 44606c3fb27SDimitry Andric 44706c3fb27SDimitry Andric uptr __sanitizer_get_allocated_size_fast(const void *p) { 44806c3fb27SDimitry Andric DCHECK_EQ(p, __sanitizer_get_allocated_begin(p)); 44906c3fb27SDimitry Andric uptr ret = AllocationSizeFast(p); 45006c3fb27SDimitry Andric DCHECK_EQ(ret, __sanitizer_get_allocated_size(p)); 45106c3fb27SDimitry Andric return ret; 45206c3fb27SDimitry Andric } 45306c3fb27SDimitry Andric 45406c3fb27SDimitry Andric void __sanitizer_purge_allocator() { allocator.ForceReleaseToOS(); } 455