1 1.1 mrg //===-- hwasan_allocator.cpp ------------------------ ---------------------===// 2 1.1 mrg // 3 1.1 mrg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 1.1 mrg // See https://llvm.org/LICENSE.txt for license information. 5 1.1 mrg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 1.1 mrg // 7 1.1 mrg //===----------------------------------------------------------------------===// 8 1.1 mrg // 9 1.1 mrg // This file is a part of HWAddressSanitizer. 10 1.1 mrg // 11 1.1 mrg // HWAddressSanitizer allocator. 12 1.1 mrg //===----------------------------------------------------------------------===// 13 1.1 mrg 14 1.1 mrg #include "sanitizer_common/sanitizer_atomic.h" 15 1.1 mrg #include "sanitizer_common/sanitizer_errno.h" 16 1.1 mrg #include "sanitizer_common/sanitizer_stackdepot.h" 17 1.1 mrg #include "hwasan.h" 18 1.1 mrg #include "hwasan_allocator.h" 19 1.1 mrg #include "hwasan_checks.h" 20 1.1 mrg #include "hwasan_mapping.h" 21 1.1 mrg #include "hwasan_malloc_bisect.h" 22 1.1 mrg #include "hwasan_thread.h" 23 1.1 mrg #include "hwasan_report.h" 24 1.1 mrg 25 1.1 mrg namespace __hwasan { 26 1.1 mrg 27 1.1 mrg static Allocator allocator; 28 1.1 mrg static AllocatorCache fallback_allocator_cache; 29 1.1 mrg static SpinMutex fallback_mutex; 30 1.1 mrg static atomic_uint8_t hwasan_allocator_tagging_enabled; 31 1.1 mrg 32 1.1 mrg static constexpr tag_t kFallbackAllocTag = 0xBB & kTagMask; 33 1.1 mrg static constexpr tag_t kFallbackFreeTag = 0xBC; 34 1.1 mrg 35 1.1 mrg enum RightAlignMode { 36 1.1 mrg kRightAlignNever, 37 1.1 mrg kRightAlignSometimes, 38 1.1 mrg kRightAlignAlways 39 1.1 mrg }; 40 1.1 mrg 41 1.1 mrg // Initialized in HwasanAllocatorInit, an never changed. 42 1.1 mrg static ALIGNED(16) u8 tail_magic[kShadowAlignment - 1]; 43 1.1 mrg 44 1.1 mrg bool HwasanChunkView::IsAllocated() const { 45 1.1 mrg return metadata_ && metadata_->alloc_context_id && 46 1.1 mrg metadata_->get_requested_size(); 47 1.1 mrg } 48 1.1 mrg 49 1.1 mrg // Aligns the 'addr' right to the granule boundary. 50 1.1 mrg static uptr AlignRight(uptr addr, uptr requested_size) { 51 1.1 mrg uptr tail_size = requested_size % kShadowAlignment; 52 1.1 mrg if (!tail_size) return addr; 53 1.1 mrg return addr + kShadowAlignment - tail_size; 54 1.1 mrg } 55 1.1 mrg 56 1.1 mrg uptr HwasanChunkView::Beg() const { 57 1.1 mrg if (metadata_ && metadata_->right_aligned) 58 1.1 mrg return AlignRight(block_, metadata_->get_requested_size()); 59 1.1 mrg return block_; 60 1.1 mrg } 61 1.1 mrg uptr HwasanChunkView::End() const { 62 1.1 mrg return Beg() + UsedSize(); 63 1.1 mrg } 64 1.1 mrg uptr HwasanChunkView::UsedSize() const { 65 1.1 mrg return metadata_->get_requested_size(); 66 1.1 mrg } 67 1.1 mrg u32 HwasanChunkView::GetAllocStackId() const { 68 1.1 mrg return metadata_->alloc_context_id; 69 1.1 mrg } 70 1.1 mrg 71 1.1 mrg uptr HwasanChunkView::ActualSize() const { 72 1.1 mrg return allocator.GetActuallyAllocatedSize(reinterpret_cast<void *>(block_)); 73 1.1 mrg } 74 1.1 mrg 75 1.1 mrg bool HwasanChunkView::FromSmallHeap() const { 76 1.1 mrg return allocator.FromPrimary(reinterpret_cast<void *>(block_)); 77 1.1 mrg } 78 1.1 mrg 79 1.1 mrg void GetAllocatorStats(AllocatorStatCounters s) { 80 1.1 mrg allocator.GetStats(s); 81 1.1 mrg } 82 1.1 mrg 83 1.1 mrg uptr GetAliasRegionStart() { 84 1.1 mrg #if defined(HWASAN_ALIASING_MODE) 85 1.1 mrg constexpr uptr kAliasRegionOffset = 1ULL << (kTaggableRegionCheckShift - 1); 86 1.1 mrg uptr AliasRegionStart = 87 1.1 mrg __hwasan_shadow_memory_dynamic_address + kAliasRegionOffset; 88 1.1 mrg 89 1.1 mrg CHECK_EQ(AliasRegionStart >> kTaggableRegionCheckShift, 90 1.1 mrg __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift); 91 1.1 mrg CHECK_EQ( 92 1.1 mrg (AliasRegionStart + kAliasRegionOffset - 1) >> kTaggableRegionCheckShift, 93 1.1 mrg __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift); 94 1.1 mrg return AliasRegionStart; 95 1.1 mrg #else 96 1.1 mrg return 0; 97 1.1 mrg #endif 98 1.1 mrg } 99 1.1 mrg 100 1.1 mrg void HwasanAllocatorInit() { 101 1.1 mrg atomic_store_relaxed(&hwasan_allocator_tagging_enabled, 102 1.1 mrg !flags()->disable_allocator_tagging); 103 1.1 mrg SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null); 104 1.1 mrg allocator.Init(common_flags()->allocator_release_to_os_interval_ms, 105 1.1 mrg GetAliasRegionStart()); 106 1.1 mrg for (uptr i = 0; i < sizeof(tail_magic); i++) 107 1.1 mrg tail_magic[i] = GetCurrentThread()->GenerateRandomTag(); 108 1.1 mrg } 109 1.1 mrg 110 1.1 mrg void HwasanAllocatorLock() { allocator.ForceLock(); } 111 1.1 mrg 112 1.1 mrg void HwasanAllocatorUnlock() { allocator.ForceUnlock(); } 113 1.1 mrg 114 1.1 mrg void AllocatorSwallowThreadLocalCache(AllocatorCache *cache) { 115 1.1 mrg allocator.SwallowCache(cache); 116 1.1 mrg } 117 1.1 mrg 118 1.1 mrg static uptr TaggedSize(uptr size) { 119 1.1 mrg if (!size) size = 1; 120 1.1 mrg uptr new_size = RoundUpTo(size, kShadowAlignment); 121 1.1 mrg CHECK_GE(new_size, size); 122 1.1 mrg return new_size; 123 1.1 mrg } 124 1.1 mrg 125 1.1 mrg static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment, 126 1.1 mrg bool zeroise) { 127 1.1 mrg if (orig_size > kMaxAllowedMallocSize) { 128 1.1 mrg if (AllocatorMayReturnNull()) { 129 1.1 mrg Report("WARNING: HWAddressSanitizer failed to allocate 0x%zx bytes\n", 130 1.1 mrg orig_size); 131 1.1 mrg return nullptr; 132 1.1 mrg } 133 1.1 mrg ReportAllocationSizeTooBig(orig_size, kMaxAllowedMallocSize, stack); 134 1.1 mrg } 135 1.1 mrg 136 1.1 mrg alignment = Max(alignment, kShadowAlignment); 137 1.1 mrg uptr size = TaggedSize(orig_size); 138 1.1 mrg Thread *t = GetCurrentThread(); 139 1.1 mrg void *allocated; 140 1.1 mrg if (t) { 141 1.1 mrg allocated = allocator.Allocate(t->allocator_cache(), size, alignment); 142 1.1 mrg } else { 143 1.1 mrg SpinMutexLock l(&fallback_mutex); 144 1.1 mrg AllocatorCache *cache = &fallback_allocator_cache; 145 1.1 mrg allocated = allocator.Allocate(cache, size, alignment); 146 1.1 mrg } 147 1.1 mrg if (UNLIKELY(!allocated)) { 148 1.1 mrg SetAllocatorOutOfMemory(); 149 1.1 mrg if (AllocatorMayReturnNull()) 150 1.1 mrg return nullptr; 151 1.1 mrg ReportOutOfMemory(size, stack); 152 1.1 mrg } 153 1.1 mrg Metadata *meta = 154 1.1 mrg reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated)); 155 1.1 mrg meta->set_requested_size(orig_size); 156 1.1 mrg meta->alloc_context_id = StackDepotPut(*stack); 157 1.1 mrg meta->right_aligned = false; 158 1.1 mrg if (zeroise) { 159 1.1 mrg internal_memset(allocated, 0, size); 160 1.1 mrg } else if (flags()->max_malloc_fill_size > 0) { 161 1.1 mrg uptr fill_size = Min(size, (uptr)flags()->max_malloc_fill_size); 162 1.1 mrg internal_memset(allocated, flags()->malloc_fill_byte, fill_size); 163 1.1 mrg } 164 1.1 mrg if (size != orig_size) { 165 1.1 mrg u8 *tail = reinterpret_cast<u8 *>(allocated) + orig_size; 166 1.1 mrg uptr tail_length = size - orig_size; 167 1.1 mrg internal_memcpy(tail, tail_magic, tail_length - 1); 168 1.1 mrg // Short granule is excluded from magic tail, so we explicitly untag. 169 1.1 mrg tail[tail_length - 1] = 0; 170 1.1 mrg } 171 1.1 mrg 172 1.1 mrg void *user_ptr = allocated; 173 1.1 mrg // Tagging can only be skipped when both tag_in_malloc and tag_in_free are 174 1.1 mrg // false. When tag_in_malloc = false and tag_in_free = true malloc needs to 175 1.1 mrg // retag to 0. 176 1.1 mrg if (InTaggableRegion(reinterpret_cast<uptr>(user_ptr)) && 177 1.1 mrg (flags()->tag_in_malloc || flags()->tag_in_free) && 178 1.1 mrg atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) { 179 1.1 mrg if (flags()->tag_in_malloc && malloc_bisect(stack, orig_size)) { 180 1.1 mrg tag_t tag = t ? t->GenerateRandomTag() : kFallbackAllocTag; 181 1.1 mrg uptr tag_size = orig_size ? orig_size : 1; 182 1.1 mrg uptr full_granule_size = RoundDownTo(tag_size, kShadowAlignment); 183 1.1 mrg user_ptr = 184 1.1 mrg (void *)TagMemoryAligned((uptr)user_ptr, full_granule_size, tag); 185 1.1 mrg if (full_granule_size != tag_size) { 186 1.1 mrg u8 *short_granule = 187 1.1 mrg reinterpret_cast<u8 *>(allocated) + full_granule_size; 188 1.1 mrg TagMemoryAligned((uptr)short_granule, kShadowAlignment, 189 1.1 mrg tag_size % kShadowAlignment); 190 1.1 mrg short_granule[kShadowAlignment - 1] = tag; 191 1.1 mrg } 192 1.1 mrg } else { 193 1.1 mrg user_ptr = (void *)TagMemoryAligned((uptr)user_ptr, size, 0); 194 1.1 mrg } 195 1.1 mrg } 196 1.1 mrg 197 1.1 mrg HWASAN_MALLOC_HOOK(user_ptr, size); 198 1.1 mrg return user_ptr; 199 1.1 mrg } 200 1.1 mrg 201 1.1 mrg static bool PointerAndMemoryTagsMatch(void *tagged_ptr) { 202 1.1 mrg CHECK(tagged_ptr); 203 1.1 mrg uptr tagged_uptr = reinterpret_cast<uptr>(tagged_ptr); 204 1.1 mrg if (!InTaggableRegion(tagged_uptr)) 205 1.1 mrg return true; 206 1.1 mrg tag_t mem_tag = *reinterpret_cast<tag_t *>( 207 1.1 mrg MemToShadow(reinterpret_cast<uptr>(UntagPtr(tagged_ptr)))); 208 1.1 mrg return PossiblyShortTagMatches(mem_tag, tagged_uptr, 1); 209 1.1 mrg } 210 1.1 mrg 211 1.1 mrg static bool CheckInvalidFree(StackTrace *stack, void *untagged_ptr, 212 1.1 mrg void *tagged_ptr) { 213 1.1 mrg // This function can return true if halt_on_error is false. 214 1.1 mrg if (!MemIsApp(reinterpret_cast<uptr>(untagged_ptr)) || 215 1.1 mrg !PointerAndMemoryTagsMatch(tagged_ptr)) { 216 1.1 mrg ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr)); 217 1.1 mrg return true; 218 1.1 mrg } 219 1.1 mrg return false; 220 1.1 mrg } 221 1.1 mrg 222 1.1 mrg static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { 223 1.1 mrg CHECK(tagged_ptr); 224 1.1 mrg HWASAN_FREE_HOOK(tagged_ptr); 225 1.1 mrg 226 1.1 mrg bool in_taggable_region = 227 1.1 mrg InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr)); 228 1.1 mrg void *untagged_ptr = in_taggable_region ? UntagPtr(tagged_ptr) : tagged_ptr; 229 1.1 mrg 230 1.1 mrg if (CheckInvalidFree(stack, untagged_ptr, tagged_ptr)) 231 1.1 mrg return; 232 1.1 mrg 233 1.1 mrg void *aligned_ptr = reinterpret_cast<void *>( 234 1.1 mrg RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment)); 235 1.1 mrg tag_t pointer_tag = GetTagFromPointer(reinterpret_cast<uptr>(tagged_ptr)); 236 1.1 mrg Metadata *meta = 237 1.1 mrg reinterpret_cast<Metadata *>(allocator.GetMetaData(aligned_ptr)); 238 1.1 mrg if (!meta) { 239 1.1 mrg ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr)); 240 1.1 mrg return; 241 1.1 mrg } 242 1.1 mrg uptr orig_size = meta->get_requested_size(); 243 1.1 mrg u32 free_context_id = StackDepotPut(*stack); 244 1.1 mrg u32 alloc_context_id = meta->alloc_context_id; 245 1.1 mrg 246 1.1 mrg // Check tail magic. 247 1.1 mrg uptr tagged_size = TaggedSize(orig_size); 248 1.1 mrg if (flags()->free_checks_tail_magic && orig_size && 249 1.1 mrg tagged_size != orig_size) { 250 1.1 mrg uptr tail_size = tagged_size - orig_size - 1; 251 1.1 mrg CHECK_LT(tail_size, kShadowAlignment); 252 1.1 mrg void *tail_beg = reinterpret_cast<void *>( 253 1.1 mrg reinterpret_cast<uptr>(aligned_ptr) + orig_size); 254 1.1 mrg tag_t short_granule_memtag = *(reinterpret_cast<tag_t *>( 255 1.1 mrg reinterpret_cast<uptr>(tail_beg) + tail_size)); 256 1.1 mrg if (tail_size && 257 1.1 mrg (internal_memcmp(tail_beg, tail_magic, tail_size) || 258 1.1 mrg (in_taggable_region && pointer_tag != short_granule_memtag))) 259 1.1 mrg ReportTailOverwritten(stack, reinterpret_cast<uptr>(tagged_ptr), 260 1.1 mrg orig_size, tail_magic); 261 1.1 mrg } 262 1.1 mrg 263 1.1 mrg meta->set_requested_size(0); 264 1.1 mrg meta->alloc_context_id = 0; 265 1.1 mrg // This memory will not be reused by anyone else, so we are free to keep it 266 1.1 mrg // poisoned. 267 1.1 mrg Thread *t = GetCurrentThread(); 268 1.1 mrg if (flags()->max_free_fill_size > 0) { 269 1.1 mrg uptr fill_size = 270 1.1 mrg Min(TaggedSize(orig_size), (uptr)flags()->max_free_fill_size); 271 1.1 mrg internal_memset(aligned_ptr, flags()->free_fill_byte, fill_size); 272 1.1 mrg } 273 1.1 mrg if (in_taggable_region && flags()->tag_in_free && malloc_bisect(stack, 0) && 274 1.1 mrg atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) { 275 1.1 mrg // Always store full 8-bit tags on free to maximize UAF detection. 276 1.1 mrg tag_t tag; 277 1.1 mrg if (t) { 278 1.1 mrg // Make sure we are not using a short granule tag as a poison tag. This 279 1.1 mrg // would make us attempt to read the memory on a UaF. 280 1.1 mrg // The tag can be zero if tagging is disabled on this thread. 281 1.1 mrg do { 282 1.1 mrg tag = t->GenerateRandomTag(/*num_bits=*/8); 283 1.1 mrg } while ( 284 1.1 mrg UNLIKELY((tag < kShadowAlignment || tag == pointer_tag) && tag != 0)); 285 1.1 mrg } else { 286 1.1 mrg static_assert(kFallbackFreeTag >= kShadowAlignment, 287 1.1 mrg "fallback tag must not be a short granule tag."); 288 1.1 mrg tag = kFallbackFreeTag; 289 1.1 mrg } 290 1.1 mrg TagMemoryAligned(reinterpret_cast<uptr>(aligned_ptr), TaggedSize(orig_size), 291 1.1 mrg tag); 292 1.1 mrg } 293 1.1 mrg if (t) { 294 1.1 mrg allocator.Deallocate(t->allocator_cache(), aligned_ptr); 295 1.1 mrg if (auto *ha = t->heap_allocations()) 296 1.1 mrg ha->push({reinterpret_cast<uptr>(tagged_ptr), alloc_context_id, 297 1.1 mrg free_context_id, static_cast<u32>(orig_size)}); 298 1.1 mrg } else { 299 1.1 mrg SpinMutexLock l(&fallback_mutex); 300 1.1 mrg AllocatorCache *cache = &fallback_allocator_cache; 301 1.1 mrg allocator.Deallocate(cache, aligned_ptr); 302 1.1 mrg } 303 1.1 mrg } 304 1.1 mrg 305 1.1 mrg static void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old, 306 1.1 mrg uptr new_size, uptr alignment) { 307 1.1 mrg void *untagged_ptr_old = 308 1.1 mrg InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr_old)) 309 1.1 mrg ? UntagPtr(tagged_ptr_old) 310 1.1 mrg : tagged_ptr_old; 311 1.1 mrg if (CheckInvalidFree(stack, untagged_ptr_old, tagged_ptr_old)) 312 1.1 mrg return nullptr; 313 1.1 mrg void *tagged_ptr_new = 314 1.1 mrg HwasanAllocate(stack, new_size, alignment, false /*zeroise*/); 315 1.1 mrg if (tagged_ptr_old && tagged_ptr_new) { 316 1.1 mrg Metadata *meta = 317 1.1 mrg reinterpret_cast<Metadata *>(allocator.GetMetaData(untagged_ptr_old)); 318 1.1 mrg internal_memcpy( 319 1.1 mrg UntagPtr(tagged_ptr_new), untagged_ptr_old, 320 1.1 mrg Min(new_size, static_cast<uptr>(meta->get_requested_size()))); 321 1.1 mrg HwasanDeallocate(stack, tagged_ptr_old); 322 1.1 mrg } 323 1.1 mrg return tagged_ptr_new; 324 1.1 mrg } 325 1.1 mrg 326 1.1 mrg static void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) { 327 1.1 mrg if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { 328 1.1 mrg if (AllocatorMayReturnNull()) 329 1.1 mrg return nullptr; 330 1.1 mrg ReportCallocOverflow(nmemb, size, stack); 331 1.1 mrg } 332 1.1 mrg return HwasanAllocate(stack, nmemb * size, sizeof(u64), true); 333 1.1 mrg } 334 1.1 mrg 335 1.1 mrg HwasanChunkView FindHeapChunkByAddress(uptr address) { 336 1.1 mrg if (!allocator.PointerIsMine(reinterpret_cast<void *>(address))) 337 1.1 mrg return HwasanChunkView(); 338 1.1 mrg void *block = allocator.GetBlockBegin(reinterpret_cast<void*>(address)); 339 1.1 mrg if (!block) 340 1.1 mrg return HwasanChunkView(); 341 1.1 mrg Metadata *metadata = 342 1.1 mrg reinterpret_cast<Metadata*>(allocator.GetMetaData(block)); 343 1.1 mrg return HwasanChunkView(reinterpret_cast<uptr>(block), metadata); 344 1.1 mrg } 345 1.1 mrg 346 1.1 mrg static uptr AllocationSize(const void *tagged_ptr) { 347 1.1 mrg const void *untagged_ptr = UntagPtr(tagged_ptr); 348 1.1 mrg if (!untagged_ptr) return 0; 349 1.1 mrg const void *beg = allocator.GetBlockBegin(untagged_ptr); 350 1.1 mrg Metadata *b = (Metadata *)allocator.GetMetaData(untagged_ptr); 351 1.1 mrg if (b->right_aligned) { 352 1.1 mrg if (beg != reinterpret_cast<void *>(RoundDownTo( 353 1.1 mrg reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment))) 354 1.1 mrg return 0; 355 1.1 mrg } else { 356 1.1 mrg if (beg != untagged_ptr) return 0; 357 1.1 mrg } 358 1.1 mrg return b->get_requested_size(); 359 1.1 mrg } 360 1.1 mrg 361 1.1 mrg void *hwasan_malloc(uptr size, StackTrace *stack) { 362 1.1 mrg return SetErrnoOnNull(HwasanAllocate(stack, size, sizeof(u64), false)); 363 1.1 mrg } 364 1.1 mrg 365 1.1 mrg void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack) { 366 1.1 mrg return SetErrnoOnNull(HwasanCalloc(stack, nmemb, size)); 367 1.1 mrg } 368 1.1 mrg 369 1.1 mrg void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack) { 370 1.1 mrg if (!ptr) 371 1.1 mrg return SetErrnoOnNull(HwasanAllocate(stack, size, sizeof(u64), false)); 372 1.1 mrg if (size == 0) { 373 1.1 mrg HwasanDeallocate(stack, ptr); 374 1.1 mrg return nullptr; 375 1.1 mrg } 376 1.1 mrg return SetErrnoOnNull(HwasanReallocate(stack, ptr, size, sizeof(u64))); 377 1.1 mrg } 378 1.1 mrg 379 1.1 mrg void *hwasan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack) { 380 1.1 mrg if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { 381 1.1 mrg errno = errno_ENOMEM; 382 1.1 mrg if (AllocatorMayReturnNull()) 383 1.1 mrg return nullptr; 384 1.1 mrg ReportReallocArrayOverflow(nmemb, size, stack); 385 1.1 mrg } 386 1.1 mrg return hwasan_realloc(ptr, nmemb * size, stack); 387 1.1 mrg } 388 1.1 mrg 389 1.1 mrg void *hwasan_valloc(uptr size, StackTrace *stack) { 390 1.1 mrg return SetErrnoOnNull( 391 1.1 mrg HwasanAllocate(stack, size, GetPageSizeCached(), false)); 392 1.1 mrg } 393 1.1 mrg 394 1.1 mrg void *hwasan_pvalloc(uptr size, StackTrace *stack) { 395 1.1 mrg uptr PageSize = GetPageSizeCached(); 396 1.1 mrg if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) { 397 1.1 mrg errno = errno_ENOMEM; 398 1.1 mrg if (AllocatorMayReturnNull()) 399 1.1 mrg return nullptr; 400 1.1 mrg ReportPvallocOverflow(size, stack); 401 1.1 mrg } 402 1.1 mrg // pvalloc(0) should allocate one page. 403 1.1 mrg size = size ? RoundUpTo(size, PageSize) : PageSize; 404 1.1 mrg return SetErrnoOnNull(HwasanAllocate(stack, size, PageSize, false)); 405 1.1 mrg } 406 1.1 mrg 407 1.1 mrg void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) { 408 1.1 mrg if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) { 409 1.1 mrg errno = errno_EINVAL; 410 1.1 mrg if (AllocatorMayReturnNull()) 411 1.1 mrg return nullptr; 412 1.1 mrg ReportInvalidAlignedAllocAlignment(size, alignment, stack); 413 1.1 mrg } 414 1.1 mrg return SetErrnoOnNull(HwasanAllocate(stack, size, alignment, false)); 415 1.1 mrg } 416 1.1 mrg 417 1.1 mrg void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack) { 418 1.1 mrg if (UNLIKELY(!IsPowerOfTwo(alignment))) { 419 1.1 mrg errno = errno_EINVAL; 420 1.1 mrg if (AllocatorMayReturnNull()) 421 1.1 mrg return nullptr; 422 1.1 mrg ReportInvalidAllocationAlignment(alignment, stack); 423 1.1 mrg } 424 1.1 mrg return SetErrnoOnNull(HwasanAllocate(stack, size, alignment, false)); 425 1.1 mrg } 426 1.1 mrg 427 1.1 mrg int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size, 428 1.1 mrg StackTrace *stack) { 429 1.1 mrg if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { 430 1.1 mrg if (AllocatorMayReturnNull()) 431 1.1 mrg return errno_EINVAL; 432 1.1 mrg ReportInvalidPosixMemalignAlignment(alignment, stack); 433 1.1 mrg } 434 1.1 mrg void *ptr = HwasanAllocate(stack, size, alignment, false); 435 1.1 mrg if (UNLIKELY(!ptr)) 436 1.1 mrg // OOM error is already taken care of by HwasanAllocate. 437 1.1 mrg return errno_ENOMEM; 438 1.1 mrg CHECK(IsAligned((uptr)ptr, alignment)); 439 1.1 mrg *memptr = ptr; 440 1.1 mrg return 0; 441 1.1 mrg } 442 1.1 mrg 443 1.1 mrg void hwasan_free(void *ptr, StackTrace *stack) { 444 1.1 mrg return HwasanDeallocate(stack, ptr); 445 1.1 mrg } 446 1.1 mrg 447 1.1 mrg } // namespace __hwasan 448 1.1 mrg 449 1.1 mrg using namespace __hwasan; 450 1.1 mrg 451 1.1 mrg void __hwasan_enable_allocator_tagging() { 452 1.1 mrg atomic_store_relaxed(&hwasan_allocator_tagging_enabled, 1); 453 1.1 mrg } 454 1.1 mrg 455 1.1 mrg void __hwasan_disable_allocator_tagging() { 456 1.1 mrg atomic_store_relaxed(&hwasan_allocator_tagging_enabled, 0); 457 1.1 mrg } 458 1.1 mrg 459 1.1 mrg uptr __sanitizer_get_current_allocated_bytes() { 460 1.1 mrg uptr stats[AllocatorStatCount]; 461 1.1 mrg allocator.GetStats(stats); 462 1.1 mrg return stats[AllocatorStatAllocated]; 463 1.1 mrg } 464 1.1 mrg 465 1.1 mrg uptr __sanitizer_get_heap_size() { 466 1.1 mrg uptr stats[AllocatorStatCount]; 467 1.1 mrg allocator.GetStats(stats); 468 1.1 mrg return stats[AllocatorStatMapped]; 469 1.1 mrg } 470 1.1 mrg 471 1.1 mrg uptr __sanitizer_get_free_bytes() { return 1; } 472 1.1 mrg 473 1.1 mrg uptr __sanitizer_get_unmapped_bytes() { return 1; } 474 1.1 mrg 475 1.1 mrg uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; } 476 1.1 mrg 477 1.1 mrg int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; } 478 1.1 mrg 479 1.1 mrg uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); } 480