1 //===-- asan_allocator2.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 AddressSanitizer, an address sanity checker. 11 // 12 // Implementation of ASan's memory allocator, 2-nd version. 13 // This variant uses the allocator from sanitizer_common, i.e. the one shared 14 // with ThreadSanitizer and MemorySanitizer. 15 // 16 //===----------------------------------------------------------------------===// 17 #include "asan_allocator.h" 18 19 #include "asan_mapping.h" 20 #include "asan_poisoning.h" 21 #include "asan_report.h" 22 #include "asan_stack.h" 23 #include "asan_thread.h" 24 #include "sanitizer_common/sanitizer_allocator_interface.h" 25 #include "sanitizer_common/sanitizer_flags.h" 26 #include "sanitizer_common/sanitizer_internal_defs.h" 27 #include "sanitizer_common/sanitizer_list.h" 28 #include "sanitizer_common/sanitizer_stackdepot.h" 29 #include "sanitizer_common/sanitizer_quarantine.h" 30 #include "lsan/lsan_common.h" 31 32 namespace __asan { 33 34 void AsanMapUnmapCallback::OnMap(uptr p, uptr size) const { 35 PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic); 36 // Statistics. 37 AsanStats &thread_stats = GetCurrentThreadStats(); 38 thread_stats.mmaps++; 39 thread_stats.mmaped += size; 40 } 41 void AsanMapUnmapCallback::OnUnmap(uptr p, uptr size) const { 42 PoisonShadow(p, size, 0); 43 // We are about to unmap a chunk of user memory. 44 // Mark the corresponding shadow memory as not needed. 45 FlushUnneededASanShadowMemory(p, size); 46 // Statistics. 47 AsanStats &thread_stats = GetCurrentThreadStats(); 48 thread_stats.munmaps++; 49 thread_stats.munmaped += size; 50 } 51 52 // We can not use THREADLOCAL because it is not supported on some of the 53 // platforms we care about (OSX 10.6, Android). 54 // static THREADLOCAL AllocatorCache cache; 55 AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) { 56 CHECK(ms); 57 return &ms->allocator2_cache; 58 } 59 60 static Allocator allocator; 61 62 static const uptr kMaxAllowedMallocSize = 63 FIRST_32_SECOND_64(3UL << 30, 64UL << 30); 64 65 static const uptr kMaxThreadLocalQuarantine = 66 FIRST_32_SECOND_64(1 << 18, 1 << 20); 67 68 // Every chunk of memory allocated by this allocator can be in one of 3 states: 69 // CHUNK_AVAILABLE: the chunk is in the free list and ready to be allocated. 70 // CHUNK_ALLOCATED: the chunk is allocated and not yet freed. 71 // CHUNK_QUARANTINE: the chunk was freed and put into quarantine zone. 72 enum { 73 CHUNK_AVAILABLE = 0, // 0 is the default value even if we didn't set it. 74 CHUNK_ALLOCATED = 2, 75 CHUNK_QUARANTINE = 3 76 }; 77 78 // Valid redzone sizes are 16, 32, 64, ... 2048, so we encode them in 3 bits. 79 // We use adaptive redzones: for larger allocation larger redzones are used. 80 static u32 RZLog2Size(u32 rz_log) { 81 CHECK_LT(rz_log, 8); 82 return 16 << rz_log; 83 } 84 85 static u32 RZSize2Log(u32 rz_size) { 86 CHECK_GE(rz_size, 16); 87 CHECK_LE(rz_size, 2048); 88 CHECK(IsPowerOfTwo(rz_size)); 89 u32 res = Log2(rz_size) - 4; 90 CHECK_EQ(rz_size, RZLog2Size(res)); 91 return res; 92 } 93 94 static uptr ComputeRZLog(uptr user_requested_size) { 95 u32 rz_log = 96 user_requested_size <= 64 - 16 ? 0 : 97 user_requested_size <= 128 - 32 ? 1 : 98 user_requested_size <= 512 - 64 ? 2 : 99 user_requested_size <= 4096 - 128 ? 3 : 100 user_requested_size <= (1 << 14) - 256 ? 4 : 101 user_requested_size <= (1 << 15) - 512 ? 5 : 102 user_requested_size <= (1 << 16) - 1024 ? 6 : 7; 103 return Min(Max(rz_log, RZSize2Log(flags()->redzone)), 104 RZSize2Log(flags()->max_redzone)); 105 } 106 107 // The memory chunk allocated from the underlying allocator looks like this: 108 // L L L L L L H H U U U U U U R R 109 // L -- left redzone words (0 or more bytes) 110 // H -- ChunkHeader (16 bytes), which is also a part of the left redzone. 111 // U -- user memory. 112 // R -- right redzone (0 or more bytes) 113 // ChunkBase consists of ChunkHeader and other bytes that overlap with user 114 // memory. 115 116 // If the left redzone is greater than the ChunkHeader size we store a magic 117 // value in the first uptr word of the memory block and store the address of 118 // ChunkBase in the next uptr. 119 // M B L L L L L L L L L H H U U U U U U 120 // | ^ 121 // ---------------------| 122 // M -- magic value kAllocBegMagic 123 // B -- address of ChunkHeader pointing to the first 'H' 124 static const uptr kAllocBegMagic = 0xCC6E96B9; 125 126 struct ChunkHeader { 127 // 1-st 8 bytes. 128 u32 chunk_state : 8; // Must be first. 129 u32 alloc_tid : 24; 130 131 u32 free_tid : 24; 132 u32 from_memalign : 1; 133 u32 alloc_type : 2; 134 u32 rz_log : 3; 135 u32 lsan_tag : 2; 136 // 2-nd 8 bytes 137 // This field is used for small sizes. For large sizes it is equal to 138 // SizeClassMap::kMaxSize and the actual size is stored in the 139 // SecondaryAllocator's metadata. 140 u32 user_requested_size; 141 u32 alloc_context_id; 142 }; 143 144 struct ChunkBase : ChunkHeader { 145 // Header2, intersects with user memory. 146 u32 free_context_id; 147 }; 148 149 static const uptr kChunkHeaderSize = sizeof(ChunkHeader); 150 static const uptr kChunkHeader2Size = sizeof(ChunkBase) - kChunkHeaderSize; 151 COMPILER_CHECK(kChunkHeaderSize == 16); 152 COMPILER_CHECK(kChunkHeader2Size <= 16); 153 154 struct AsanChunk: ChunkBase { 155 uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; } 156 uptr UsedSize(bool locked_version = false) { 157 if (user_requested_size != SizeClassMap::kMaxSize) 158 return user_requested_size; 159 return *reinterpret_cast<uptr *>( 160 allocator.GetMetaData(AllocBeg(locked_version))); 161 } 162 void *AllocBeg(bool locked_version = false) { 163 if (from_memalign) { 164 if (locked_version) 165 return allocator.GetBlockBeginFastLocked( 166 reinterpret_cast<void *>(this)); 167 return allocator.GetBlockBegin(reinterpret_cast<void *>(this)); 168 } 169 return reinterpret_cast<void*>(Beg() - RZLog2Size(rz_log)); 170 } 171 // If we don't use stack depot, we store the alloc/free stack traces 172 // in the chunk itself. 173 u32 *AllocStackBeg() { 174 return (u32*)(Beg() - RZLog2Size(rz_log)); 175 } 176 uptr AllocStackSize() { 177 CHECK_LE(RZLog2Size(rz_log), kChunkHeaderSize); 178 return (RZLog2Size(rz_log) - kChunkHeaderSize) / sizeof(u32); 179 } 180 u32 *FreeStackBeg() { 181 return (u32*)(Beg() + kChunkHeader2Size); 182 } 183 uptr FreeStackSize() { 184 if (user_requested_size < kChunkHeader2Size) return 0; 185 uptr available = RoundUpTo(user_requested_size, SHADOW_GRANULARITY); 186 return (available - kChunkHeader2Size) / sizeof(u32); 187 } 188 bool AddrIsInside(uptr addr, bool locked_version = false) { 189 return (addr >= Beg()) && (addr < Beg() + UsedSize(locked_version)); 190 } 191 }; 192 193 bool AsanChunkView::IsValid() { 194 return chunk_ != 0 && chunk_->chunk_state != CHUNK_AVAILABLE; 195 } 196 uptr AsanChunkView::Beg() { return chunk_->Beg(); } 197 uptr AsanChunkView::End() { return Beg() + UsedSize(); } 198 uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); } 199 uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; } 200 uptr AsanChunkView::FreeTid() { return chunk_->free_tid; } 201 202 static void GetStackTraceFromId(u32 id, StackTrace *stack) { 203 CHECK(id); 204 uptr size = 0; 205 const uptr *trace = StackDepotGet(id, &size); 206 CHECK(trace); 207 stack->CopyFrom(trace, size); 208 } 209 210 void AsanChunkView::GetAllocStack(StackTrace *stack) { 211 GetStackTraceFromId(chunk_->alloc_context_id, stack); 212 } 213 214 void AsanChunkView::GetFreeStack(StackTrace *stack) { 215 GetStackTraceFromId(chunk_->free_context_id, stack); 216 } 217 218 struct QuarantineCallback; 219 typedef Quarantine<QuarantineCallback, AsanChunk> AsanQuarantine; 220 typedef AsanQuarantine::Cache QuarantineCache; 221 static AsanQuarantine quarantine(LINKER_INITIALIZED); 222 static QuarantineCache fallback_quarantine_cache(LINKER_INITIALIZED); 223 static AllocatorCache fallback_allocator_cache; 224 static SpinMutex fallback_mutex; 225 226 QuarantineCache *GetQuarantineCache(AsanThreadLocalMallocStorage *ms) { 227 CHECK(ms); 228 CHECK_LE(sizeof(QuarantineCache), sizeof(ms->quarantine_cache)); 229 return reinterpret_cast<QuarantineCache *>(ms->quarantine_cache); 230 } 231 232 struct QuarantineCallback { 233 explicit QuarantineCallback(AllocatorCache *cache) 234 : cache_(cache) { 235 } 236 237 void Recycle(AsanChunk *m) { 238 CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE); 239 atomic_store((atomic_uint8_t*)m, CHUNK_AVAILABLE, memory_order_relaxed); 240 CHECK_NE(m->alloc_tid, kInvalidTid); 241 CHECK_NE(m->free_tid, kInvalidTid); 242 PoisonShadow(m->Beg(), 243 RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), 244 kAsanHeapLeftRedzoneMagic); 245 void *p = reinterpret_cast<void *>(m->AllocBeg()); 246 if (p != m) { 247 uptr *alloc_magic = reinterpret_cast<uptr *>(p); 248 CHECK_EQ(alloc_magic[0], kAllocBegMagic); 249 // Clear the magic value, as allocator internals may overwrite the 250 // contents of deallocated chunk, confusing GetAsanChunk lookup. 251 alloc_magic[0] = 0; 252 CHECK_EQ(alloc_magic[1], reinterpret_cast<uptr>(m)); 253 } 254 255 // Statistics. 256 AsanStats &thread_stats = GetCurrentThreadStats(); 257 thread_stats.real_frees++; 258 thread_stats.really_freed += m->UsedSize(); 259 260 allocator.Deallocate(cache_, p); 261 } 262 263 void *Allocate(uptr size) { 264 return allocator.Allocate(cache_, size, 1, false); 265 } 266 267 void Deallocate(void *p) { 268 allocator.Deallocate(cache_, p); 269 } 270 271 AllocatorCache *cache_; 272 }; 273 274 void InitializeAllocator() { 275 allocator.Init(); 276 quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine); 277 } 278 279 void ReInitializeAllocator() { 280 quarantine.Init((uptr)flags()->quarantine_size, kMaxThreadLocalQuarantine); 281 } 282 283 static void *Allocate(uptr size, uptr alignment, StackTrace *stack, 284 AllocType alloc_type, bool can_fill) { 285 if (UNLIKELY(!asan_inited)) 286 AsanInitFromRtl(); 287 Flags &fl = *flags(); 288 CHECK(stack); 289 const uptr min_alignment = SHADOW_GRANULARITY; 290 if (alignment < min_alignment) 291 alignment = min_alignment; 292 if (size == 0) { 293 // We'd be happy to avoid allocating memory for zero-size requests, but 294 // some programs/tests depend on this behavior and assume that malloc would 295 // not return NULL even for zero-size allocations. Moreover, it looks like 296 // operator new should never return NULL, and results of consecutive "new" 297 // calls must be different even if the allocated size is zero. 298 size = 1; 299 } 300 CHECK(IsPowerOfTwo(alignment)); 301 uptr rz_log = ComputeRZLog(size); 302 uptr rz_size = RZLog2Size(rz_log); 303 uptr rounded_size = RoundUpTo(Max(size, kChunkHeader2Size), alignment); 304 uptr needed_size = rounded_size + rz_size; 305 if (alignment > min_alignment) 306 needed_size += alignment; 307 bool using_primary_allocator = true; 308 // If we are allocating from the secondary allocator, there will be no 309 // automatic right redzone, so add the right redzone manually. 310 if (!PrimaryAllocator::CanAllocate(needed_size, alignment)) { 311 needed_size += rz_size; 312 using_primary_allocator = false; 313 } 314 CHECK(IsAligned(needed_size, min_alignment)); 315 if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) { 316 Report("WARNING: AddressSanitizer failed to allocate %p bytes\n", 317 (void*)size); 318 return AllocatorReturnNull(); 319 } 320 321 AsanThread *t = GetCurrentThread(); 322 void *allocated; 323 if (t) { 324 AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage()); 325 allocated = allocator.Allocate(cache, needed_size, 8, false); 326 } else { 327 SpinMutexLock l(&fallback_mutex); 328 AllocatorCache *cache = &fallback_allocator_cache; 329 allocated = allocator.Allocate(cache, needed_size, 8, false); 330 } 331 332 if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && flags()->poison_heap) { 333 // Heap poisoning is enabled, but the allocator provides an unpoisoned 334 // chunk. This is possible if flags()->poison_heap was disabled for some 335 // time, for example, due to flags()->start_disabled. 336 // Anyway, poison the block before using it for anything else. 337 uptr allocated_size = allocator.GetActuallyAllocatedSize(allocated); 338 PoisonShadow((uptr)allocated, allocated_size, kAsanHeapLeftRedzoneMagic); 339 } 340 341 uptr alloc_beg = reinterpret_cast<uptr>(allocated); 342 uptr alloc_end = alloc_beg + needed_size; 343 uptr beg_plus_redzone = alloc_beg + rz_size; 344 uptr user_beg = beg_plus_redzone; 345 if (!IsAligned(user_beg, alignment)) 346 user_beg = RoundUpTo(user_beg, alignment); 347 uptr user_end = user_beg + size; 348 CHECK_LE(user_end, alloc_end); 349 uptr chunk_beg = user_beg - kChunkHeaderSize; 350 AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg); 351 m->alloc_type = alloc_type; 352 m->rz_log = rz_log; 353 u32 alloc_tid = t ? t->tid() : 0; 354 m->alloc_tid = alloc_tid; 355 CHECK_EQ(alloc_tid, m->alloc_tid); // Does alloc_tid fit into the bitfield? 356 m->free_tid = kInvalidTid; 357 m->from_memalign = user_beg != beg_plus_redzone; 358 if (alloc_beg != chunk_beg) { 359 CHECK_LE(alloc_beg+ 2 * sizeof(uptr), chunk_beg); 360 reinterpret_cast<uptr *>(alloc_beg)[0] = kAllocBegMagic; 361 reinterpret_cast<uptr *>(alloc_beg)[1] = chunk_beg; 362 } 363 if (using_primary_allocator) { 364 CHECK(size); 365 m->user_requested_size = size; 366 CHECK(allocator.FromPrimary(allocated)); 367 } else { 368 CHECK(!allocator.FromPrimary(allocated)); 369 m->user_requested_size = SizeClassMap::kMaxSize; 370 uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(allocated)); 371 meta[0] = size; 372 meta[1] = chunk_beg; 373 } 374 375 m->alloc_context_id = StackDepotPut(stack->trace, stack->size); 376 377 uptr size_rounded_down_to_granularity = RoundDownTo(size, SHADOW_GRANULARITY); 378 // Unpoison the bulk of the memory region. 379 if (size_rounded_down_to_granularity) 380 PoisonShadow(user_beg, size_rounded_down_to_granularity, 0); 381 // Deal with the end of the region if size is not aligned to granularity. 382 if (size != size_rounded_down_to_granularity && fl.poison_heap) { 383 u8 *shadow = (u8*)MemToShadow(user_beg + size_rounded_down_to_granularity); 384 *shadow = fl.poison_partial ? (size & (SHADOW_GRANULARITY - 1)) : 0; 385 } 386 387 AsanStats &thread_stats = GetCurrentThreadStats(); 388 thread_stats.mallocs++; 389 thread_stats.malloced += size; 390 thread_stats.malloced_redzones += needed_size - size; 391 uptr class_id = Min(kNumberOfSizeClasses, SizeClassMap::ClassID(needed_size)); 392 thread_stats.malloced_by_size[class_id]++; 393 if (needed_size > SizeClassMap::kMaxSize) 394 thread_stats.malloc_large++; 395 396 void *res = reinterpret_cast<void *>(user_beg); 397 if (can_fill && fl.max_malloc_fill_size) { 398 uptr fill_size = Min(size, (uptr)fl.max_malloc_fill_size); 399 REAL(memset)(res, fl.malloc_fill_byte, fill_size); 400 } 401 #if CAN_SANITIZE_LEAKS 402 m->lsan_tag = __lsan::DisabledInThisThread() ? __lsan::kIgnored 403 : __lsan::kDirectlyLeaked; 404 #endif 405 // Must be the last mutation of metadata in this function. 406 atomic_store((atomic_uint8_t *)m, CHUNK_ALLOCATED, memory_order_release); 407 ASAN_MALLOC_HOOK(res, size); 408 return res; 409 } 410 411 static void ReportInvalidFree(void *ptr, u8 chunk_state, StackTrace *stack) { 412 if (chunk_state == CHUNK_QUARANTINE) 413 ReportDoubleFree((uptr)ptr, stack); 414 else 415 ReportFreeNotMalloced((uptr)ptr, stack); 416 } 417 418 static void AtomicallySetQuarantineFlag(AsanChunk *m, 419 void *ptr, StackTrace *stack) { 420 u8 old_chunk_state = CHUNK_ALLOCATED; 421 // Flip the chunk_state atomically to avoid race on double-free. 422 if (!atomic_compare_exchange_strong((atomic_uint8_t*)m, &old_chunk_state, 423 CHUNK_QUARANTINE, memory_order_acquire)) 424 ReportInvalidFree(ptr, old_chunk_state, stack); 425 CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state); 426 } 427 428 // Expects the chunk to already be marked as quarantined by using 429 // AtomicallySetQuarantineFlag. 430 static void QuarantineChunk(AsanChunk *m, void *ptr, 431 StackTrace *stack, AllocType alloc_type) { 432 CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE); 433 434 if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch) 435 ReportAllocTypeMismatch((uptr)ptr, stack, 436 (AllocType)m->alloc_type, (AllocType)alloc_type); 437 438 CHECK_GE(m->alloc_tid, 0); 439 if (SANITIZER_WORDSIZE == 64) // On 32-bits this resides in user area. 440 CHECK_EQ(m->free_tid, kInvalidTid); 441 AsanThread *t = GetCurrentThread(); 442 m->free_tid = t ? t->tid() : 0; 443 m->free_context_id = StackDepotPut(stack->trace, stack->size); 444 // Poison the region. 445 PoisonShadow(m->Beg(), 446 RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), 447 kAsanHeapFreeMagic); 448 449 AsanStats &thread_stats = GetCurrentThreadStats(); 450 thread_stats.frees++; 451 thread_stats.freed += m->UsedSize(); 452 453 // Push into quarantine. 454 if (t) { 455 AsanThreadLocalMallocStorage *ms = &t->malloc_storage(); 456 AllocatorCache *ac = GetAllocatorCache(ms); 457 quarantine.Put(GetQuarantineCache(ms), QuarantineCallback(ac), 458 m, m->UsedSize()); 459 } else { 460 SpinMutexLock l(&fallback_mutex); 461 AllocatorCache *ac = &fallback_allocator_cache; 462 quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac), 463 m, m->UsedSize()); 464 } 465 } 466 467 static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) { 468 uptr p = reinterpret_cast<uptr>(ptr); 469 if (p == 0) return; 470 471 uptr chunk_beg = p - kChunkHeaderSize; 472 AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg); 473 ASAN_FREE_HOOK(ptr); 474 // Must mark the chunk as quarantined before any changes to its metadata. 475 AtomicallySetQuarantineFlag(m, ptr, stack); 476 QuarantineChunk(m, ptr, stack, alloc_type); 477 } 478 479 static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) { 480 CHECK(old_ptr && new_size); 481 uptr p = reinterpret_cast<uptr>(old_ptr); 482 uptr chunk_beg = p - kChunkHeaderSize; 483 AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg); 484 485 AsanStats &thread_stats = GetCurrentThreadStats(); 486 thread_stats.reallocs++; 487 thread_stats.realloced += new_size; 488 489 void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true); 490 if (new_ptr) { 491 u8 chunk_state = m->chunk_state; 492 if (chunk_state != CHUNK_ALLOCATED) 493 ReportInvalidFree(old_ptr, chunk_state, stack); 494 CHECK_NE(REAL(memcpy), (void*)0); 495 uptr memcpy_size = Min(new_size, m->UsedSize()); 496 // If realloc() races with free(), we may start copying freed memory. 497 // However, we will report racy double-free later anyway. 498 REAL(memcpy)(new_ptr, old_ptr, memcpy_size); 499 Deallocate(old_ptr, stack, FROM_MALLOC); 500 } 501 return new_ptr; 502 } 503 504 // Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg). 505 static AsanChunk *GetAsanChunk(void *alloc_beg) { 506 if (!alloc_beg) return 0; 507 if (!allocator.FromPrimary(alloc_beg)) { 508 uptr *meta = reinterpret_cast<uptr *>(allocator.GetMetaData(alloc_beg)); 509 AsanChunk *m = reinterpret_cast<AsanChunk *>(meta[1]); 510 return m; 511 } 512 uptr *alloc_magic = reinterpret_cast<uptr *>(alloc_beg); 513 if (alloc_magic[0] == kAllocBegMagic) 514 return reinterpret_cast<AsanChunk *>(alloc_magic[1]); 515 return reinterpret_cast<AsanChunk *>(alloc_beg); 516 } 517 518 static AsanChunk *GetAsanChunkByAddr(uptr p) { 519 void *alloc_beg = allocator.GetBlockBegin(reinterpret_cast<void *>(p)); 520 return GetAsanChunk(alloc_beg); 521 } 522 523 // Allocator must be locked when this function is called. 524 static AsanChunk *GetAsanChunkByAddrFastLocked(uptr p) { 525 void *alloc_beg = 526 allocator.GetBlockBeginFastLocked(reinterpret_cast<void *>(p)); 527 return GetAsanChunk(alloc_beg); 528 } 529 530 static uptr AllocationSize(uptr p) { 531 AsanChunk *m = GetAsanChunkByAddr(p); 532 if (!m) return 0; 533 if (m->chunk_state != CHUNK_ALLOCATED) return 0; 534 if (m->Beg() != p) return 0; 535 return m->UsedSize(); 536 } 537 538 // We have an address between two chunks, and we want to report just one. 539 AsanChunk *ChooseChunk(uptr addr, 540 AsanChunk *left_chunk, AsanChunk *right_chunk) { 541 // Prefer an allocated chunk over freed chunk and freed chunk 542 // over available chunk. 543 if (left_chunk->chunk_state != right_chunk->chunk_state) { 544 if (left_chunk->chunk_state == CHUNK_ALLOCATED) 545 return left_chunk; 546 if (right_chunk->chunk_state == CHUNK_ALLOCATED) 547 return right_chunk; 548 if (left_chunk->chunk_state == CHUNK_QUARANTINE) 549 return left_chunk; 550 if (right_chunk->chunk_state == CHUNK_QUARANTINE) 551 return right_chunk; 552 } 553 // Same chunk_state: choose based on offset. 554 sptr l_offset = 0, r_offset = 0; 555 CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset)); 556 CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset)); 557 if (l_offset < r_offset) 558 return left_chunk; 559 return right_chunk; 560 } 561 562 AsanChunkView FindHeapChunkByAddress(uptr addr) { 563 AsanChunk *m1 = GetAsanChunkByAddr(addr); 564 if (!m1) return AsanChunkView(m1); 565 sptr offset = 0; 566 if (AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) { 567 // The address is in the chunk's left redzone, so maybe it is actually 568 // a right buffer overflow from the other chunk to the left. 569 // Search a bit to the left to see if there is another chunk. 570 AsanChunk *m2 = 0; 571 for (uptr l = 1; l < GetPageSizeCached(); l++) { 572 m2 = GetAsanChunkByAddr(addr - l); 573 if (m2 == m1) continue; // Still the same chunk. 574 break; 575 } 576 if (m2 && AsanChunkView(m2).AddrIsAtRight(addr, 1, &offset)) 577 m1 = ChooseChunk(addr, m2, m1); 578 } 579 return AsanChunkView(m1); 580 } 581 582 void AsanThreadLocalMallocStorage::CommitBack() { 583 AllocatorCache *ac = GetAllocatorCache(this); 584 quarantine.Drain(GetQuarantineCache(this), QuarantineCallback(ac)); 585 allocator.SwallowCache(GetAllocatorCache(this)); 586 } 587 588 void PrintInternalAllocatorStats() { 589 allocator.PrintStats(); 590 } 591 592 void *asan_memalign(uptr alignment, uptr size, StackTrace *stack, 593 AllocType alloc_type) { 594 return Allocate(size, alignment, stack, alloc_type, true); 595 } 596 597 void asan_free(void *ptr, StackTrace *stack, AllocType alloc_type) { 598 Deallocate(ptr, stack, alloc_type); 599 } 600 601 void *asan_malloc(uptr size, StackTrace *stack) { 602 return Allocate(size, 8, stack, FROM_MALLOC, true); 603 } 604 605 void *asan_calloc(uptr nmemb, uptr size, StackTrace *stack) { 606 if (CallocShouldReturnNullDueToOverflow(size, nmemb)) 607 return AllocatorReturnNull(); 608 void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false); 609 // If the memory comes from the secondary allocator no need to clear it 610 // as it comes directly from mmap. 611 if (ptr && allocator.FromPrimary(ptr)) 612 REAL(memset)(ptr, 0, nmemb * size); 613 return ptr; 614 } 615 616 void *asan_realloc(void *p, uptr size, StackTrace *stack) { 617 if (p == 0) 618 return Allocate(size, 8, stack, FROM_MALLOC, true); 619 if (size == 0) { 620 Deallocate(p, stack, FROM_MALLOC); 621 return 0; 622 } 623 return Reallocate(p, size, stack); 624 } 625 626 void *asan_valloc(uptr size, StackTrace *stack) { 627 return Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true); 628 } 629 630 void *asan_pvalloc(uptr size, StackTrace *stack) { 631 uptr PageSize = GetPageSizeCached(); 632 size = RoundUpTo(size, PageSize); 633 if (size == 0) { 634 // pvalloc(0) should allocate one page. 635 size = PageSize; 636 } 637 return Allocate(size, PageSize, stack, FROM_MALLOC, true); 638 } 639 640 int asan_posix_memalign(void **memptr, uptr alignment, uptr size, 641 StackTrace *stack) { 642 void *ptr = Allocate(size, alignment, stack, FROM_MALLOC, true); 643 CHECK(IsAligned((uptr)ptr, alignment)); 644 *memptr = ptr; 645 return 0; 646 } 647 648 uptr asan_malloc_usable_size(void *ptr, uptr pc, uptr bp) { 649 if (ptr == 0) return 0; 650 uptr usable_size = AllocationSize(reinterpret_cast<uptr>(ptr)); 651 if (flags()->check_malloc_usable_size && (usable_size == 0)) { 652 GET_STACK_TRACE_FATAL(pc, bp); 653 ReportMallocUsableSizeNotOwned((uptr)ptr, &stack); 654 } 655 return usable_size; 656 } 657 658 uptr asan_mz_size(const void *ptr) { 659 return AllocationSize(reinterpret_cast<uptr>(ptr)); 660 } 661 662 void asan_mz_force_lock() { 663 allocator.ForceLock(); 664 fallback_mutex.Lock(); 665 } 666 667 void asan_mz_force_unlock() { 668 fallback_mutex.Unlock(); 669 allocator.ForceUnlock(); 670 } 671 672 } // namespace __asan 673 674 // --- Implementation of LSan-specific functions --- {{{1 675 namespace __lsan { 676 void LockAllocator() { 677 __asan::allocator.ForceLock(); 678 } 679 680 void UnlockAllocator() { 681 __asan::allocator.ForceUnlock(); 682 } 683 684 void GetAllocatorGlobalRange(uptr *begin, uptr *end) { 685 *begin = (uptr)&__asan::allocator; 686 *end = *begin + sizeof(__asan::allocator); 687 } 688 689 uptr PointsIntoChunk(void* p) { 690 uptr addr = reinterpret_cast<uptr>(p); 691 __asan::AsanChunk *m = __asan::GetAsanChunkByAddrFastLocked(addr); 692 if (!m) return 0; 693 uptr chunk = m->Beg(); 694 if (m->chunk_state != __asan::CHUNK_ALLOCATED) 695 return 0; 696 if (m->AddrIsInside(addr, /*locked_version=*/true)) 697 return chunk; 698 if (IsSpecialCaseOfOperatorNew0(chunk, m->UsedSize(/*locked_version*/ true), 699 addr)) 700 return chunk; 701 return 0; 702 } 703 704 uptr GetUserBegin(uptr chunk) { 705 __asan::AsanChunk *m = 706 __asan::GetAsanChunkByAddrFastLocked(chunk); 707 CHECK(m); 708 return m->Beg(); 709 } 710 711 LsanMetadata::LsanMetadata(uptr chunk) { 712 metadata_ = reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize); 713 } 714 715 bool LsanMetadata::allocated() const { 716 __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); 717 return m->chunk_state == __asan::CHUNK_ALLOCATED; 718 } 719 720 ChunkTag LsanMetadata::tag() const { 721 __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); 722 return static_cast<ChunkTag>(m->lsan_tag); 723 } 724 725 void LsanMetadata::set_tag(ChunkTag value) { 726 __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); 727 m->lsan_tag = value; 728 } 729 730 uptr LsanMetadata::requested_size() const { 731 __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); 732 return m->UsedSize(/*locked_version=*/true); 733 } 734 735 u32 LsanMetadata::stack_trace_id() const { 736 __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); 737 return m->alloc_context_id; 738 } 739 740 void ForEachChunk(ForEachChunkCallback callback, void *arg) { 741 __asan::allocator.ForEachChunk(callback, arg); 742 } 743 744 IgnoreObjectResult IgnoreObjectLocked(const void *p) { 745 uptr addr = reinterpret_cast<uptr>(p); 746 __asan::AsanChunk *m = __asan::GetAsanChunkByAddr(addr); 747 if (!m) return kIgnoreObjectInvalid; 748 if ((m->chunk_state == __asan::CHUNK_ALLOCATED) && m->AddrIsInside(addr)) { 749 if (m->lsan_tag == kIgnored) 750 return kIgnoreObjectAlreadyIgnored; 751 m->lsan_tag = __lsan::kIgnored; 752 return kIgnoreObjectSuccess; 753 } else { 754 return kIgnoreObjectInvalid; 755 } 756 } 757 } // namespace __lsan 758 759 // ---------------------- Interface ---------------- {{{1 760 using namespace __asan; // NOLINT 761 762 // ASan allocator doesn't reserve extra bytes, so normally we would 763 // just return "size". We don't want to expose our redzone sizes, etc here. 764 uptr __sanitizer_get_estimated_allocated_size(uptr size) { 765 return size; 766 } 767 uptr __asan_get_estimated_allocated_size(uptr size) { 768 return __sanitizer_get_estimated_allocated_size(size); 769 } 770 771 int __sanitizer_get_ownership(const void *p) { 772 uptr ptr = reinterpret_cast<uptr>(p); 773 return (AllocationSize(ptr) > 0); 774 } 775 int __asan_get_ownership(const void *p) { 776 return __sanitizer_get_ownership(p); 777 } 778 779 uptr __sanitizer_get_allocated_size(const void *p) { 780 if (p == 0) return 0; 781 uptr ptr = reinterpret_cast<uptr>(p); 782 uptr allocated_size = AllocationSize(ptr); 783 // Die if p is not malloced or if it is already freed. 784 if (allocated_size == 0) { 785 GET_STACK_TRACE_FATAL_HERE; 786 ReportSanitizerGetAllocatedSizeNotOwned(ptr, &stack); 787 } 788 return allocated_size; 789 } 790 uptr __asan_get_allocated_size(const void *p) { 791 return __sanitizer_get_allocated_size(p); 792 } 793 794 #if !SANITIZER_SUPPORTS_WEAK_HOOKS 795 // Provide default (no-op) implementation of malloc hooks. 796 extern "C" { 797 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 798 void __asan_malloc_hook(void *ptr, uptr size) { 799 (void)ptr; 800 (void)size; 801 } 802 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 803 void __asan_free_hook(void *ptr) { 804 (void)ptr; 805 } 806 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 807 void __sanitizer_malloc_hook(void *ptr, uptr size) { 808 (void)ptr; 809 (void)size; 810 } 811 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE 812 void __sanitizer_free_hook(void *ptr) { 813 (void)ptr; 814 } 815 } // extern "C" 816 #endif 817