1 1.1 mrg //===-- asan_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 AddressSanitizer, an address sanity checker. 10 1.1 mrg // 11 1.1 mrg // Implementation of ASan's memory allocator, 2-nd version. 12 1.1 mrg // This variant uses the allocator from sanitizer_common, i.e. the one shared 13 1.1 mrg // with ThreadSanitizer and MemorySanitizer. 14 1.1 mrg // 15 1.1 mrg //===----------------------------------------------------------------------===// 16 1.1 mrg 17 1.1 mrg #include "asan_allocator.h" 18 1.1 mrg 19 1.1 mrg #include "asan_mapping.h" 20 1.1 mrg #include "asan_poisoning.h" 21 1.1 mrg #include "asan_report.h" 22 1.1 mrg #include "asan_stack.h" 23 1.1 mrg #include "asan_thread.h" 24 1.1 mrg #include "lsan/lsan_common.h" 25 1.1 mrg #include "sanitizer_common/sanitizer_allocator_checks.h" 26 1.1 mrg #include "sanitizer_common/sanitizer_allocator_interface.h" 27 1.1 mrg #include "sanitizer_common/sanitizer_errno.h" 28 1.1 mrg #include "sanitizer_common/sanitizer_flags.h" 29 1.1 mrg #include "sanitizer_common/sanitizer_internal_defs.h" 30 1.1 mrg #include "sanitizer_common/sanitizer_list.h" 31 1.1 mrg #include "sanitizer_common/sanitizer_quarantine.h" 32 1.1 mrg #include "sanitizer_common/sanitizer_stackdepot.h" 33 1.1 mrg 34 1.1 mrg namespace __asan { 35 1.1 mrg 36 1.1 mrg // Valid redzone sizes are 16, 32, 64, ... 2048, so we encode them in 3 bits. 37 1.1 mrg // We use adaptive redzones: for larger allocation larger redzones are used. 38 1.1 mrg static u32 RZLog2Size(u32 rz_log) { 39 1.1 mrg CHECK_LT(rz_log, 8); 40 1.1 mrg return 16 << rz_log; 41 1.1 mrg } 42 1.1 mrg 43 1.1 mrg static u32 RZSize2Log(u32 rz_size) { 44 1.1 mrg CHECK_GE(rz_size, 16); 45 1.1 mrg CHECK_LE(rz_size, 2048); 46 1.1 mrg CHECK(IsPowerOfTwo(rz_size)); 47 1.1 mrg u32 res = Log2(rz_size) - 4; 48 1.1 mrg CHECK_EQ(rz_size, RZLog2Size(res)); 49 1.1 mrg return res; 50 1.1 mrg } 51 1.1 mrg 52 1.1 mrg static AsanAllocator &get_allocator(); 53 1.1 mrg 54 1.1 mrg static void AtomicContextStore(volatile atomic_uint64_t *atomic_context, 55 1.1 mrg u32 tid, u32 stack) { 56 1.1 mrg u64 context = tid; 57 1.1 mrg context <<= 32; 58 1.1 mrg context += stack; 59 1.1 mrg atomic_store(atomic_context, context, memory_order_relaxed); 60 1.1 mrg } 61 1.1 mrg 62 1.1 mrg static void AtomicContextLoad(const volatile atomic_uint64_t *atomic_context, 63 1.1 mrg u32 &tid, u32 &stack) { 64 1.1 mrg u64 context = atomic_load(atomic_context, memory_order_relaxed); 65 1.1 mrg stack = context; 66 1.1 mrg context >>= 32; 67 1.1 mrg tid = context; 68 1.1 mrg } 69 1.1 mrg 70 1.1 mrg // The memory chunk allocated from the underlying allocator looks like this: 71 1.1 mrg // L L L L L L H H U U U U U U R R 72 1.1 mrg // L -- left redzone words (0 or more bytes) 73 1.1 mrg // H -- ChunkHeader (16 bytes), which is also a part of the left redzone. 74 1.1 mrg // U -- user memory. 75 1.1 mrg // R -- right redzone (0 or more bytes) 76 1.1 mrg // ChunkBase consists of ChunkHeader and other bytes that overlap with user 77 1.1 mrg // memory. 78 1.1 mrg 79 1.1 mrg // If the left redzone is greater than the ChunkHeader size we store a magic 80 1.1 mrg // value in the first uptr word of the memory block and store the address of 81 1.1 mrg // ChunkBase in the next uptr. 82 1.1 mrg // M B L L L L L L L L L H H U U U U U U 83 1.1 mrg // | ^ 84 1.1 mrg // ---------------------| 85 1.1 mrg // M -- magic value kAllocBegMagic 86 1.1 mrg // B -- address of ChunkHeader pointing to the first 'H' 87 1.1 mrg 88 1.1 mrg class ChunkHeader { 89 1.1 mrg public: 90 1.1 mrg atomic_uint8_t chunk_state; 91 1.1 mrg u8 alloc_type : 2; 92 1.1 mrg u8 lsan_tag : 2; 93 1.1 mrg 94 1.1 mrg // align < 8 -> 0 95 1.1 mrg // else -> log2(min(align, 512)) - 2 96 1.1 mrg u8 user_requested_alignment_log : 3; 97 1.1 mrg 98 1.1 mrg private: 99 1.1 mrg u16 user_requested_size_hi; 100 1.1 mrg u32 user_requested_size_lo; 101 1.1 mrg atomic_uint64_t alloc_context_id; 102 1.1 mrg 103 1.1 mrg public: 104 1.1 mrg uptr UsedSize() const { 105 1.1 mrg static_assert(sizeof(user_requested_size_lo) == 4, 106 1.1 mrg "Expression below requires this"); 107 1.1 mrg return FIRST_32_SECOND_64(0, ((uptr)user_requested_size_hi << 32)) + 108 1.1 mrg user_requested_size_lo; 109 1.1 mrg } 110 1.1 mrg 111 1.1 mrg void SetUsedSize(uptr size) { 112 1.1 mrg user_requested_size_lo = size; 113 1.1 mrg static_assert(sizeof(user_requested_size_lo) == 4, 114 1.1 mrg "Expression below requires this"); 115 1.1 mrg user_requested_size_hi = FIRST_32_SECOND_64(0, size >> 32); 116 1.1 mrg CHECK_EQ(UsedSize(), size); 117 1.1 mrg } 118 1.1 mrg 119 1.1 mrg void SetAllocContext(u32 tid, u32 stack) { 120 1.1 mrg AtomicContextStore(&alloc_context_id, tid, stack); 121 1.1 mrg } 122 1.1 mrg 123 1.1 mrg void GetAllocContext(u32 &tid, u32 &stack) const { 124 1.1 mrg AtomicContextLoad(&alloc_context_id, tid, stack); 125 1.1 mrg } 126 1.1 mrg }; 127 1.1 mrg 128 1.1 mrg class ChunkBase : public ChunkHeader { 129 1.1 mrg atomic_uint64_t free_context_id; 130 1.1 mrg 131 1.1 mrg public: 132 1.1 mrg void SetFreeContext(u32 tid, u32 stack) { 133 1.1 mrg AtomicContextStore(&free_context_id, tid, stack); 134 1.1 mrg } 135 1.1 mrg 136 1.1 mrg void GetFreeContext(u32 &tid, u32 &stack) const { 137 1.1 mrg AtomicContextLoad(&free_context_id, tid, stack); 138 1.1 mrg } 139 1.1 mrg }; 140 1.1 mrg 141 1.1 mrg static const uptr kChunkHeaderSize = sizeof(ChunkHeader); 142 1.1 mrg static const uptr kChunkHeader2Size = sizeof(ChunkBase) - kChunkHeaderSize; 143 1.1 mrg COMPILER_CHECK(kChunkHeaderSize == 16); 144 1.1 mrg COMPILER_CHECK(kChunkHeader2Size <= 16); 145 1.1 mrg 146 1.1 mrg enum { 147 1.1 mrg // Either just allocated by underlying allocator, but AsanChunk is not yet 148 1.1 mrg // ready, or almost returned to undelying allocator and AsanChunk is already 149 1.1 mrg // meaningless. 150 1.1 mrg CHUNK_INVALID = 0, 151 1.1 mrg // The chunk is allocated and not yet freed. 152 1.1 mrg CHUNK_ALLOCATED = 2, 153 1.1 mrg // The chunk was freed and put into quarantine zone. 154 1.1 mrg CHUNK_QUARANTINE = 3, 155 1.1 mrg }; 156 1.1 mrg 157 1.1 mrg class AsanChunk : public ChunkBase { 158 1.1 mrg public: 159 1.1 mrg uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; } 160 1.1 mrg bool AddrIsInside(uptr addr) { 161 1.1 mrg return (addr >= Beg()) && (addr < Beg() + UsedSize()); 162 1.1 mrg } 163 1.1 mrg }; 164 1.1 mrg 165 1.1 mrg class LargeChunkHeader { 166 1.1 mrg static constexpr uptr kAllocBegMagic = 167 1.1 mrg FIRST_32_SECOND_64(0xCC6E96B9, 0xCC6E96B9CC6E96B9ULL); 168 1.1 mrg atomic_uintptr_t magic; 169 1.1 mrg AsanChunk *chunk_header; 170 1.1 mrg 171 1.1 mrg public: 172 1.1 mrg AsanChunk *Get() const { 173 1.1 mrg return atomic_load(&magic, memory_order_acquire) == kAllocBegMagic 174 1.1 mrg ? chunk_header 175 1.1 mrg : nullptr; 176 1.1 mrg } 177 1.1 mrg 178 1.1 mrg void Set(AsanChunk *p) { 179 1.1 mrg if (p) { 180 1.1 mrg chunk_header = p; 181 1.1 mrg atomic_store(&magic, kAllocBegMagic, memory_order_release); 182 1.1 mrg return; 183 1.1 mrg } 184 1.1 mrg 185 1.1 mrg uptr old = kAllocBegMagic; 186 1.1 mrg if (!atomic_compare_exchange_strong(&magic, &old, 0, 187 1.1 mrg memory_order_release)) { 188 1.1 mrg CHECK_EQ(old, kAllocBegMagic); 189 1.1 mrg } 190 1.1 mrg } 191 1.1 mrg }; 192 1.1 mrg 193 1.1 mrg struct QuarantineCallback { 194 1.1 mrg QuarantineCallback(AllocatorCache *cache, BufferedStackTrace *stack) 195 1.1 mrg : cache_(cache), 196 1.1 mrg stack_(stack) { 197 1.1 mrg } 198 1.1 mrg 199 1.1 mrg void Recycle(AsanChunk *m) { 200 1.1 mrg void *p = get_allocator().GetBlockBegin(m); 201 1.1 mrg if (p != m) { 202 1.1 mrg // Clear the magic value, as allocator internals may overwrite the 203 1.1 mrg // contents of deallocated chunk, confusing GetAsanChunk lookup. 204 1.1 mrg reinterpret_cast<LargeChunkHeader *>(p)->Set(nullptr); 205 1.1 mrg } 206 1.1 mrg 207 1.1 mrg u8 old_chunk_state = CHUNK_QUARANTINE; 208 1.1 mrg if (!atomic_compare_exchange_strong(&m->chunk_state, &old_chunk_state, 209 1.1 mrg CHUNK_INVALID, memory_order_acquire)) { 210 1.1 mrg CHECK_EQ(old_chunk_state, CHUNK_QUARANTINE); 211 1.1 mrg } 212 1.1 mrg 213 1.1 mrg PoisonShadow(m->Beg(), 214 1.1 mrg RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), 215 1.1 mrg kAsanHeapLeftRedzoneMagic); 216 1.1 mrg 217 1.1 mrg // Statistics. 218 1.1 mrg AsanStats &thread_stats = GetCurrentThreadStats(); 219 1.1 mrg thread_stats.real_frees++; 220 1.1 mrg thread_stats.really_freed += m->UsedSize(); 221 1.1 mrg 222 1.1 mrg get_allocator().Deallocate(cache_, p); 223 1.1 mrg } 224 1.1 mrg 225 1.1 mrg void *Allocate(uptr size) { 226 1.1 mrg void *res = get_allocator().Allocate(cache_, size, 1); 227 1.1 mrg // TODO(alekseys): Consider making quarantine OOM-friendly. 228 1.1 mrg if (UNLIKELY(!res)) 229 1.1 mrg ReportOutOfMemory(size, stack_); 230 1.1 mrg return res; 231 1.1 mrg } 232 1.1 mrg 233 1.1 mrg void Deallocate(void *p) { 234 1.1 mrg get_allocator().Deallocate(cache_, p); 235 1.1 mrg } 236 1.1 mrg 237 1.1 mrg private: 238 1.1 mrg AllocatorCache* const cache_; 239 1.1 mrg BufferedStackTrace* const stack_; 240 1.1 mrg }; 241 1.1 mrg 242 1.1 mrg typedef Quarantine<QuarantineCallback, AsanChunk> AsanQuarantine; 243 1.1 mrg typedef AsanQuarantine::Cache QuarantineCache; 244 1.1 mrg 245 1.1 mrg void AsanMapUnmapCallback::OnMap(uptr p, uptr size) const { 246 1.1 mrg PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic); 247 1.1 mrg // Statistics. 248 1.1 mrg AsanStats &thread_stats = GetCurrentThreadStats(); 249 1.1 mrg thread_stats.mmaps++; 250 1.1 mrg thread_stats.mmaped += size; 251 1.1 mrg } 252 1.1 mrg void AsanMapUnmapCallback::OnUnmap(uptr p, uptr size) const { 253 1.1 mrg PoisonShadow(p, size, 0); 254 1.1 mrg // We are about to unmap a chunk of user memory. 255 1.1 mrg // Mark the corresponding shadow memory as not needed. 256 1.1 mrg FlushUnneededASanShadowMemory(p, size); 257 1.1 mrg // Statistics. 258 1.1 mrg AsanStats &thread_stats = GetCurrentThreadStats(); 259 1.1 mrg thread_stats.munmaps++; 260 1.1 mrg thread_stats.munmaped += size; 261 1.1 mrg } 262 1.1 mrg 263 1.1 mrg // We can not use THREADLOCAL because it is not supported on some of the 264 1.1 mrg // platforms we care about (OSX 10.6, Android). 265 1.1 mrg // static THREADLOCAL AllocatorCache cache; 266 1.1 mrg AllocatorCache *GetAllocatorCache(AsanThreadLocalMallocStorage *ms) { 267 1.1 mrg CHECK(ms); 268 1.1 mrg return &ms->allocator_cache; 269 1.1 mrg } 270 1.1 mrg 271 1.1 mrg QuarantineCache *GetQuarantineCache(AsanThreadLocalMallocStorage *ms) { 272 1.1 mrg CHECK(ms); 273 1.1 mrg CHECK_LE(sizeof(QuarantineCache), sizeof(ms->quarantine_cache)); 274 1.1 mrg return reinterpret_cast<QuarantineCache *>(ms->quarantine_cache); 275 1.1 mrg } 276 1.1 mrg 277 1.1 mrg void AllocatorOptions::SetFrom(const Flags *f, const CommonFlags *cf) { 278 1.1 mrg quarantine_size_mb = f->quarantine_size_mb; 279 1.1 mrg thread_local_quarantine_size_kb = f->thread_local_quarantine_size_kb; 280 1.1 mrg min_redzone = f->redzone; 281 1.1 mrg max_redzone = f->max_redzone; 282 1.1 mrg may_return_null = cf->allocator_may_return_null; 283 1.1 mrg alloc_dealloc_mismatch = f->alloc_dealloc_mismatch; 284 1.1 mrg release_to_os_interval_ms = cf->allocator_release_to_os_interval_ms; 285 1.1 mrg } 286 1.1 mrg 287 1.1 mrg void AllocatorOptions::CopyTo(Flags *f, CommonFlags *cf) { 288 1.1 mrg f->quarantine_size_mb = quarantine_size_mb; 289 1.1 mrg f->thread_local_quarantine_size_kb = thread_local_quarantine_size_kb; 290 1.1 mrg f->redzone = min_redzone; 291 1.1 mrg f->max_redzone = max_redzone; 292 1.1 mrg cf->allocator_may_return_null = may_return_null; 293 1.1 mrg f->alloc_dealloc_mismatch = alloc_dealloc_mismatch; 294 1.1 mrg cf->allocator_release_to_os_interval_ms = release_to_os_interval_ms; 295 1.1 mrg } 296 1.1 mrg 297 1.1 mrg struct Allocator { 298 1.1 mrg static const uptr kMaxAllowedMallocSize = 299 1.1 mrg FIRST_32_SECOND_64(3UL << 30, 1ULL << 40); 300 1.1 mrg 301 1.1 mrg AsanAllocator allocator; 302 1.1 mrg AsanQuarantine quarantine; 303 1.1 mrg StaticSpinMutex fallback_mutex; 304 1.1 mrg AllocatorCache fallback_allocator_cache; 305 1.1 mrg QuarantineCache fallback_quarantine_cache; 306 1.1 mrg 307 1.1 mrg uptr max_user_defined_malloc_size; 308 1.1 mrg atomic_uint8_t rss_limit_exceeded; 309 1.1 mrg 310 1.1 mrg // ------------------- Options -------------------------- 311 1.1 mrg atomic_uint16_t min_redzone; 312 1.1 mrg atomic_uint16_t max_redzone; 313 1.1 mrg atomic_uint8_t alloc_dealloc_mismatch; 314 1.1 mrg 315 1.1 mrg // ------------------- Initialization ------------------------ 316 1.1 mrg explicit Allocator(LinkerInitialized) 317 1.1 mrg : quarantine(LINKER_INITIALIZED), 318 1.1 mrg fallback_quarantine_cache(LINKER_INITIALIZED) {} 319 1.1 mrg 320 1.1 mrg void CheckOptions(const AllocatorOptions &options) const { 321 1.1 mrg CHECK_GE(options.min_redzone, 16); 322 1.1 mrg CHECK_GE(options.max_redzone, options.min_redzone); 323 1.1 mrg CHECK_LE(options.max_redzone, 2048); 324 1.1 mrg CHECK(IsPowerOfTwo(options.min_redzone)); 325 1.1 mrg CHECK(IsPowerOfTwo(options.max_redzone)); 326 1.1 mrg } 327 1.1 mrg 328 1.1 mrg void SharedInitCode(const AllocatorOptions &options) { 329 1.1 mrg CheckOptions(options); 330 1.1 mrg quarantine.Init((uptr)options.quarantine_size_mb << 20, 331 1.1 mrg (uptr)options.thread_local_quarantine_size_kb << 10); 332 1.1 mrg atomic_store(&alloc_dealloc_mismatch, options.alloc_dealloc_mismatch, 333 1.1 mrg memory_order_release); 334 1.1 mrg atomic_store(&min_redzone, options.min_redzone, memory_order_release); 335 1.1 mrg atomic_store(&max_redzone, options.max_redzone, memory_order_release); 336 1.1 mrg } 337 1.1 mrg 338 1.1 mrg void InitLinkerInitialized(const AllocatorOptions &options) { 339 1.1 mrg SetAllocatorMayReturnNull(options.may_return_null); 340 1.1 mrg allocator.InitLinkerInitialized(options.release_to_os_interval_ms); 341 1.1 mrg SharedInitCode(options); 342 1.1 mrg max_user_defined_malloc_size = common_flags()->max_allocation_size_mb 343 1.1 mrg ? common_flags()->max_allocation_size_mb 344 1.1 mrg << 20 345 1.1 mrg : kMaxAllowedMallocSize; 346 1.1 mrg } 347 1.1 mrg 348 1.1 mrg bool RssLimitExceeded() { 349 1.1 mrg return atomic_load(&rss_limit_exceeded, memory_order_relaxed); 350 1.1 mrg } 351 1.1 mrg 352 1.1 mrg void SetRssLimitExceeded(bool limit_exceeded) { 353 1.1 mrg atomic_store(&rss_limit_exceeded, limit_exceeded, memory_order_relaxed); 354 1.1 mrg } 355 1.1 mrg 356 1.1 mrg void RePoisonChunk(uptr chunk) { 357 1.1 mrg // This could be a user-facing chunk (with redzones), or some internal 358 1.1 mrg // housekeeping chunk, like TransferBatch. Start by assuming the former. 359 1.1 mrg AsanChunk *ac = GetAsanChunk((void *)chunk); 360 1.1 mrg uptr allocated_size = allocator.GetActuallyAllocatedSize((void *)chunk); 361 1.1 mrg if (ac && atomic_load(&ac->chunk_state, memory_order_acquire) == 362 1.1 mrg CHUNK_ALLOCATED) { 363 1.1 mrg uptr beg = ac->Beg(); 364 1.1 mrg uptr end = ac->Beg() + ac->UsedSize(); 365 1.1 mrg uptr chunk_end = chunk + allocated_size; 366 1.1 mrg if (chunk < beg && beg < end && end <= chunk_end) { 367 1.1 mrg // Looks like a valid AsanChunk in use, poison redzones only. 368 1.1 mrg PoisonShadow(chunk, beg - chunk, kAsanHeapLeftRedzoneMagic); 369 1.1 mrg uptr end_aligned_down = RoundDownTo(end, SHADOW_GRANULARITY); 370 1.1 mrg FastPoisonShadowPartialRightRedzone( 371 1.1 mrg end_aligned_down, end - end_aligned_down, 372 1.1 mrg chunk_end - end_aligned_down, kAsanHeapLeftRedzoneMagic); 373 1.1 mrg return; 374 1.1 mrg } 375 1.1 mrg } 376 1.1 mrg 377 1.1 mrg // This is either not an AsanChunk or freed or quarantined AsanChunk. 378 1.1 mrg // In either case, poison everything. 379 1.1 mrg PoisonShadow(chunk, allocated_size, kAsanHeapLeftRedzoneMagic); 380 1.1 mrg } 381 1.1 mrg 382 1.1 mrg void ReInitialize(const AllocatorOptions &options) { 383 1.1 mrg SetAllocatorMayReturnNull(options.may_return_null); 384 1.1 mrg allocator.SetReleaseToOSIntervalMs(options.release_to_os_interval_ms); 385 1.1 mrg SharedInitCode(options); 386 1.1 mrg 387 1.1 mrg // Poison all existing allocation's redzones. 388 1.1 mrg if (CanPoisonMemory()) { 389 1.1 mrg allocator.ForceLock(); 390 1.1 mrg allocator.ForEachChunk( 391 1.1 mrg [](uptr chunk, void *alloc) { 392 1.1 mrg ((Allocator *)alloc)->RePoisonChunk(chunk); 393 1.1 mrg }, 394 1.1 mrg this); 395 1.1 mrg allocator.ForceUnlock(); 396 1.1 mrg } 397 1.1 mrg } 398 1.1 mrg 399 1.1 mrg void GetOptions(AllocatorOptions *options) const { 400 1.1 mrg options->quarantine_size_mb = quarantine.GetSize() >> 20; 401 1.1 mrg options->thread_local_quarantine_size_kb = quarantine.GetCacheSize() >> 10; 402 1.1 mrg options->min_redzone = atomic_load(&min_redzone, memory_order_acquire); 403 1.1 mrg options->max_redzone = atomic_load(&max_redzone, memory_order_acquire); 404 1.1 mrg options->may_return_null = AllocatorMayReturnNull(); 405 1.1 mrg options->alloc_dealloc_mismatch = 406 1.1 mrg atomic_load(&alloc_dealloc_mismatch, memory_order_acquire); 407 1.1 mrg options->release_to_os_interval_ms = allocator.ReleaseToOSIntervalMs(); 408 1.1 mrg } 409 1.1 mrg 410 1.1 mrg // -------------------- Helper methods. ------------------------- 411 1.1 mrg uptr ComputeRZLog(uptr user_requested_size) { 412 1.1 mrg u32 rz_log = user_requested_size <= 64 - 16 ? 0 413 1.1 mrg : user_requested_size <= 128 - 32 ? 1 414 1.1 mrg : user_requested_size <= 512 - 64 ? 2 415 1.1 mrg : user_requested_size <= 4096 - 128 ? 3 416 1.1 mrg : user_requested_size <= (1 << 14) - 256 ? 4 417 1.1 mrg : user_requested_size <= (1 << 15) - 512 ? 5 418 1.1 mrg : user_requested_size <= (1 << 16) - 1024 ? 6 419 1.1 mrg : 7; 420 1.1 mrg u32 hdr_log = RZSize2Log(RoundUpToPowerOfTwo(sizeof(ChunkHeader))); 421 1.1 mrg u32 min_log = RZSize2Log(atomic_load(&min_redzone, memory_order_acquire)); 422 1.1 mrg u32 max_log = RZSize2Log(atomic_load(&max_redzone, memory_order_acquire)); 423 1.1 mrg return Min(Max(rz_log, Max(min_log, hdr_log)), Max(max_log, hdr_log)); 424 1.1 mrg } 425 1.1 mrg 426 1.1 mrg static uptr ComputeUserRequestedAlignmentLog(uptr user_requested_alignment) { 427 1.1 mrg if (user_requested_alignment < 8) 428 1.1 mrg return 0; 429 1.1 mrg if (user_requested_alignment > 512) 430 1.1 mrg user_requested_alignment = 512; 431 1.1 mrg return Log2(user_requested_alignment) - 2; 432 1.1 mrg } 433 1.1 mrg 434 1.1 mrg static uptr ComputeUserAlignment(uptr user_requested_alignment_log) { 435 1.1 mrg if (user_requested_alignment_log == 0) 436 1.1 mrg return 0; 437 1.1 mrg return 1LL << (user_requested_alignment_log + 2); 438 1.1 mrg } 439 1.1 mrg 440 1.1 mrg // We have an address between two chunks, and we want to report just one. 441 1.1 mrg AsanChunk *ChooseChunk(uptr addr, AsanChunk *left_chunk, 442 1.1 mrg AsanChunk *right_chunk) { 443 1.1 mrg if (!left_chunk) 444 1.1 mrg return right_chunk; 445 1.1 mrg if (!right_chunk) 446 1.1 mrg return left_chunk; 447 1.1 mrg // Prefer an allocated chunk over freed chunk and freed chunk 448 1.1 mrg // over available chunk. 449 1.1 mrg u8 left_state = atomic_load(&left_chunk->chunk_state, memory_order_relaxed); 450 1.1 mrg u8 right_state = 451 1.1 mrg atomic_load(&right_chunk->chunk_state, memory_order_relaxed); 452 1.1 mrg if (left_state != right_state) { 453 1.1 mrg if (left_state == CHUNK_ALLOCATED) 454 1.1 mrg return left_chunk; 455 1.1 mrg if (right_state == CHUNK_ALLOCATED) 456 1.1 mrg return right_chunk; 457 1.1 mrg if (left_state == CHUNK_QUARANTINE) 458 1.1 mrg return left_chunk; 459 1.1 mrg if (right_state == CHUNK_QUARANTINE) 460 1.1 mrg return right_chunk; 461 1.1 mrg } 462 1.1 mrg // Same chunk_state: choose based on offset. 463 1.1 mrg sptr l_offset = 0, r_offset = 0; 464 1.1 mrg CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset)); 465 1.1 mrg CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset)); 466 1.1 mrg if (l_offset < r_offset) 467 1.1 mrg return left_chunk; 468 1.1 mrg return right_chunk; 469 1.1 mrg } 470 1.1 mrg 471 1.1 mrg bool UpdateAllocationStack(uptr addr, BufferedStackTrace *stack) { 472 1.1 mrg AsanChunk *m = GetAsanChunkByAddr(addr); 473 1.1 mrg if (!m) return false; 474 1.1 mrg if (atomic_load(&m->chunk_state, memory_order_acquire) != CHUNK_ALLOCATED) 475 1.1 mrg return false; 476 1.1 mrg if (m->Beg() != addr) return false; 477 1.1 mrg AsanThread *t = GetCurrentThread(); 478 1.1 mrg m->SetAllocContext(t ? t->tid() : kMainTid, StackDepotPut(*stack)); 479 1.1 mrg return true; 480 1.1 mrg } 481 1.1 mrg 482 1.1 mrg // -------------------- Allocation/Deallocation routines --------------- 483 1.1 mrg void *Allocate(uptr size, uptr alignment, BufferedStackTrace *stack, 484 1.1 mrg AllocType alloc_type, bool can_fill) { 485 1.1 mrg if (UNLIKELY(!asan_inited)) 486 1.1 mrg AsanInitFromRtl(); 487 1.1 mrg if (RssLimitExceeded()) { 488 1.1 mrg if (AllocatorMayReturnNull()) 489 1.1 mrg return nullptr; 490 1.1 mrg ReportRssLimitExceeded(stack); 491 1.1 mrg } 492 1.1 mrg Flags &fl = *flags(); 493 1.1 mrg CHECK(stack); 494 1.1 mrg const uptr min_alignment = SHADOW_GRANULARITY; 495 1.1 mrg const uptr user_requested_alignment_log = 496 1.1 mrg ComputeUserRequestedAlignmentLog(alignment); 497 1.1 mrg if (alignment < min_alignment) 498 1.1 mrg alignment = min_alignment; 499 1.1 mrg if (size == 0) { 500 1.1 mrg // We'd be happy to avoid allocating memory for zero-size requests, but 501 1.1 mrg // some programs/tests depend on this behavior and assume that malloc 502 1.1 mrg // would not return NULL even for zero-size allocations. Moreover, it 503 1.1 mrg // looks like operator new should never return NULL, and results of 504 1.1 mrg // consecutive "new" calls must be different even if the allocated size 505 1.1 mrg // is zero. 506 1.1 mrg size = 1; 507 1.1 mrg } 508 1.1 mrg CHECK(IsPowerOfTwo(alignment)); 509 1.1 mrg uptr rz_log = ComputeRZLog(size); 510 1.1 mrg uptr rz_size = RZLog2Size(rz_log); 511 1.1 mrg uptr rounded_size = RoundUpTo(Max(size, kChunkHeader2Size), alignment); 512 1.1 mrg uptr needed_size = rounded_size + rz_size; 513 1.1 mrg if (alignment > min_alignment) 514 1.1 mrg needed_size += alignment; 515 1.1 mrg // If we are allocating from the secondary allocator, there will be no 516 1.1 mrg // automatic right redzone, so add the right redzone manually. 517 1.1 mrg if (!PrimaryAllocator::CanAllocate(needed_size, alignment)) 518 1.1 mrg needed_size += rz_size; 519 1.1 mrg CHECK(IsAligned(needed_size, min_alignment)); 520 1.1 mrg if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize || 521 1.1 mrg size > max_user_defined_malloc_size) { 522 1.1 mrg if (AllocatorMayReturnNull()) { 523 1.1 mrg Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n", 524 1.1 mrg size); 525 1.1 mrg return nullptr; 526 1.1 mrg } 527 1.1 mrg uptr malloc_limit = 528 1.1 mrg Min(kMaxAllowedMallocSize, max_user_defined_malloc_size); 529 1.1 mrg ReportAllocationSizeTooBig(size, needed_size, malloc_limit, stack); 530 1.1 mrg } 531 1.1 mrg 532 1.1 mrg AsanThread *t = GetCurrentThread(); 533 1.1 mrg void *allocated; 534 1.1 mrg if (t) { 535 1.1 mrg AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage()); 536 1.1 mrg allocated = allocator.Allocate(cache, needed_size, 8); 537 1.1 mrg } else { 538 1.1 mrg SpinMutexLock l(&fallback_mutex); 539 1.1 mrg AllocatorCache *cache = &fallback_allocator_cache; 540 1.1 mrg allocated = allocator.Allocate(cache, needed_size, 8); 541 1.1 mrg } 542 1.1 mrg if (UNLIKELY(!allocated)) { 543 1.1 mrg SetAllocatorOutOfMemory(); 544 1.1 mrg if (AllocatorMayReturnNull()) 545 1.1 mrg return nullptr; 546 1.1 mrg ReportOutOfMemory(size, stack); 547 1.1 mrg } 548 1.1 mrg 549 1.1 mrg if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && CanPoisonMemory()) { 550 1.1 mrg // Heap poisoning is enabled, but the allocator provides an unpoisoned 551 1.1 mrg // chunk. This is possible if CanPoisonMemory() was false for some 552 1.1 mrg // time, for example, due to flags()->start_disabled. 553 1.1 mrg // Anyway, poison the block before using it for anything else. 554 1.1 mrg uptr allocated_size = allocator.GetActuallyAllocatedSize(allocated); 555 1.1 mrg PoisonShadow((uptr)allocated, allocated_size, kAsanHeapLeftRedzoneMagic); 556 1.1 mrg } 557 1.1 mrg 558 1.1 mrg uptr alloc_beg = reinterpret_cast<uptr>(allocated); 559 1.1 mrg uptr alloc_end = alloc_beg + needed_size; 560 1.1 mrg uptr user_beg = alloc_beg + rz_size; 561 1.1 mrg if (!IsAligned(user_beg, alignment)) 562 1.1 mrg user_beg = RoundUpTo(user_beg, alignment); 563 1.1 mrg uptr user_end = user_beg + size; 564 1.1 mrg CHECK_LE(user_end, alloc_end); 565 1.1 mrg uptr chunk_beg = user_beg - kChunkHeaderSize; 566 1.1 mrg AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg); 567 1.1 mrg m->alloc_type = alloc_type; 568 1.1 mrg CHECK(size); 569 1.1 mrg m->SetUsedSize(size); 570 1.1 mrg m->user_requested_alignment_log = user_requested_alignment_log; 571 1.1 mrg 572 1.1 mrg m->SetAllocContext(t ? t->tid() : kMainTid, StackDepotPut(*stack)); 573 1.1 mrg 574 1.1 mrg uptr size_rounded_down_to_granularity = 575 1.1 mrg RoundDownTo(size, SHADOW_GRANULARITY); 576 1.1 mrg // Unpoison the bulk of the memory region. 577 1.1 mrg if (size_rounded_down_to_granularity) 578 1.1 mrg PoisonShadow(user_beg, size_rounded_down_to_granularity, 0); 579 1.1 mrg // Deal with the end of the region if size is not aligned to granularity. 580 1.1 mrg if (size != size_rounded_down_to_granularity && CanPoisonMemory()) { 581 1.1 mrg u8 *shadow = 582 1.1 mrg (u8 *)MemToShadow(user_beg + size_rounded_down_to_granularity); 583 1.1 mrg *shadow = fl.poison_partial ? (size & (SHADOW_GRANULARITY - 1)) : 0; 584 1.1 mrg } 585 1.1 mrg 586 1.1 mrg AsanStats &thread_stats = GetCurrentThreadStats(); 587 1.1 mrg thread_stats.mallocs++; 588 1.1 mrg thread_stats.malloced += size; 589 1.1 mrg thread_stats.malloced_redzones += needed_size - size; 590 1.1 mrg if (needed_size > SizeClassMap::kMaxSize) 591 1.1 mrg thread_stats.malloc_large++; 592 1.1 mrg else 593 1.1 mrg thread_stats.malloced_by_size[SizeClassMap::ClassID(needed_size)]++; 594 1.1 mrg 595 1.1 mrg void *res = reinterpret_cast<void *>(user_beg); 596 1.1 mrg if (can_fill && fl.max_malloc_fill_size) { 597 1.1 mrg uptr fill_size = Min(size, (uptr)fl.max_malloc_fill_size); 598 1.1 mrg REAL(memset)(res, fl.malloc_fill_byte, fill_size); 599 1.1 mrg } 600 1.1 mrg #if CAN_SANITIZE_LEAKS 601 1.1 mrg m->lsan_tag = __lsan::DisabledInThisThread() ? __lsan::kIgnored 602 1.1 mrg : __lsan::kDirectlyLeaked; 603 1.1 mrg #endif 604 1.1 mrg // Must be the last mutation of metadata in this function. 605 1.1 mrg atomic_store(&m->chunk_state, CHUNK_ALLOCATED, memory_order_release); 606 1.1 mrg if (alloc_beg != chunk_beg) { 607 1.1 mrg CHECK_LE(alloc_beg + sizeof(LargeChunkHeader), chunk_beg); 608 1.1 mrg reinterpret_cast<LargeChunkHeader *>(alloc_beg)->Set(m); 609 1.1 mrg } 610 1.1 mrg ASAN_MALLOC_HOOK(res, size); 611 1.1 mrg return res; 612 1.1 mrg } 613 1.1 mrg 614 1.1 mrg // Set quarantine flag if chunk is allocated, issue ASan error report on 615 1.1 mrg // available and quarantined chunks. Return true on success, false otherwise. 616 1.1 mrg bool AtomicallySetQuarantineFlagIfAllocated(AsanChunk *m, void *ptr, 617 1.1 mrg BufferedStackTrace *stack) { 618 1.1 mrg u8 old_chunk_state = CHUNK_ALLOCATED; 619 1.1 mrg // Flip the chunk_state atomically to avoid race on double-free. 620 1.1 mrg if (!atomic_compare_exchange_strong(&m->chunk_state, &old_chunk_state, 621 1.1 mrg CHUNK_QUARANTINE, 622 1.1 mrg memory_order_acquire)) { 623 1.1 mrg ReportInvalidFree(ptr, old_chunk_state, stack); 624 1.1 mrg // It's not safe to push a chunk in quarantine on invalid free. 625 1.1 mrg return false; 626 1.1 mrg } 627 1.1 mrg CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state); 628 1.1 mrg // It was a user data. 629 1.1 mrg m->SetFreeContext(kInvalidTid, 0); 630 1.1 mrg return true; 631 1.1 mrg } 632 1.1 mrg 633 1.1 mrg // Expects the chunk to already be marked as quarantined by using 634 1.1 mrg // AtomicallySetQuarantineFlagIfAllocated. 635 1.1 mrg void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack) { 636 1.1 mrg CHECK_EQ(atomic_load(&m->chunk_state, memory_order_relaxed), 637 1.1 mrg CHUNK_QUARANTINE); 638 1.1 mrg AsanThread *t = GetCurrentThread(); 639 1.1 mrg m->SetFreeContext(t ? t->tid() : 0, StackDepotPut(*stack)); 640 1.1 mrg 641 1.1 mrg Flags &fl = *flags(); 642 1.1 mrg if (fl.max_free_fill_size > 0) { 643 1.1 mrg // We have to skip the chunk header, it contains free_context_id. 644 1.1 mrg uptr scribble_start = (uptr)m + kChunkHeaderSize + kChunkHeader2Size; 645 1.1 mrg if (m->UsedSize() >= kChunkHeader2Size) { // Skip Header2 in user area. 646 1.1 mrg uptr size_to_fill = m->UsedSize() - kChunkHeader2Size; 647 1.1 mrg size_to_fill = Min(size_to_fill, (uptr)fl.max_free_fill_size); 648 1.1 mrg REAL(memset)((void *)scribble_start, fl.free_fill_byte, size_to_fill); 649 1.1 mrg } 650 1.1 mrg } 651 1.1 mrg 652 1.1 mrg // Poison the region. 653 1.1 mrg PoisonShadow(m->Beg(), 654 1.1 mrg RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY), 655 1.1 mrg kAsanHeapFreeMagic); 656 1.1 mrg 657 1.1 mrg AsanStats &thread_stats = GetCurrentThreadStats(); 658 1.1 mrg thread_stats.frees++; 659 1.1 mrg thread_stats.freed += m->UsedSize(); 660 1.1 mrg 661 1.1 mrg // Push into quarantine. 662 1.1 mrg if (t) { 663 1.1 mrg AsanThreadLocalMallocStorage *ms = &t->malloc_storage(); 664 1.1 mrg AllocatorCache *ac = GetAllocatorCache(ms); 665 1.1 mrg quarantine.Put(GetQuarantineCache(ms), QuarantineCallback(ac, stack), m, 666 1.1 mrg m->UsedSize()); 667 1.1 mrg } else { 668 1.1 mrg SpinMutexLock l(&fallback_mutex); 669 1.1 mrg AllocatorCache *ac = &fallback_allocator_cache; 670 1.1 mrg quarantine.Put(&fallback_quarantine_cache, QuarantineCallback(ac, stack), 671 1.1 mrg m, m->UsedSize()); 672 1.1 mrg } 673 1.1 mrg } 674 1.1 mrg 675 1.1 mrg void Deallocate(void *ptr, uptr delete_size, uptr delete_alignment, 676 1.1 mrg BufferedStackTrace *stack, AllocType alloc_type) { 677 1.1 mrg uptr p = reinterpret_cast<uptr>(ptr); 678 1.1 mrg if (p == 0) return; 679 1.1 mrg 680 1.1 mrg uptr chunk_beg = p - kChunkHeaderSize; 681 1.1 mrg AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg); 682 1.1 mrg 683 1.1 mrg // On Windows, uninstrumented DLLs may allocate memory before ASan hooks 684 1.1 mrg // malloc. Don't report an invalid free in this case. 685 1.1 mrg if (SANITIZER_WINDOWS && 686 1.1 mrg !get_allocator().PointerIsMine(ptr)) { 687 1.1 mrg if (!IsSystemHeapAddress(p)) 688 1.1 mrg ReportFreeNotMalloced(p, stack); 689 1.1 mrg return; 690 1.1 mrg } 691 1.1 mrg 692 1.1 mrg ASAN_FREE_HOOK(ptr); 693 1.1 mrg 694 1.1 mrg // Must mark the chunk as quarantined before any changes to its metadata. 695 1.1 mrg // Do not quarantine given chunk if we failed to set CHUNK_QUARANTINE flag. 696 1.1 mrg if (!AtomicallySetQuarantineFlagIfAllocated(m, ptr, stack)) return; 697 1.1 mrg 698 1.1 mrg if (m->alloc_type != alloc_type) { 699 1.1 mrg if (atomic_load(&alloc_dealloc_mismatch, memory_order_acquire)) { 700 1.1 mrg ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type, 701 1.1 mrg (AllocType)alloc_type); 702 1.1 mrg } 703 1.1 mrg } else { 704 1.1 mrg if (flags()->new_delete_type_mismatch && 705 1.1 mrg (alloc_type == FROM_NEW || alloc_type == FROM_NEW_BR) && 706 1.1 mrg ((delete_size && delete_size != m->UsedSize()) || 707 1.1 mrg ComputeUserRequestedAlignmentLog(delete_alignment) != 708 1.1 mrg m->user_requested_alignment_log)) { 709 1.1 mrg ReportNewDeleteTypeMismatch(p, delete_size, delete_alignment, stack); 710 1.1 mrg } 711 1.1 mrg } 712 1.1 mrg 713 1.1 mrg QuarantineChunk(m, ptr, stack); 714 1.1 mrg } 715 1.1 mrg 716 1.1 mrg void *Reallocate(void *old_ptr, uptr new_size, BufferedStackTrace *stack) { 717 1.1 mrg CHECK(old_ptr && new_size); 718 1.1 mrg uptr p = reinterpret_cast<uptr>(old_ptr); 719 1.1 mrg uptr chunk_beg = p - kChunkHeaderSize; 720 1.1 mrg AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg); 721 1.1 mrg 722 1.1 mrg AsanStats &thread_stats = GetCurrentThreadStats(); 723 1.1 mrg thread_stats.reallocs++; 724 1.1 mrg thread_stats.realloced += new_size; 725 1.1 mrg 726 1.1 mrg void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true); 727 1.1 mrg if (new_ptr) { 728 1.1 mrg u8 chunk_state = atomic_load(&m->chunk_state, memory_order_acquire); 729 1.1 mrg if (chunk_state != CHUNK_ALLOCATED) 730 1.1 mrg ReportInvalidFree(old_ptr, chunk_state, stack); 731 1.1 mrg CHECK_NE(REAL(memcpy), nullptr); 732 1.1 mrg uptr memcpy_size = Min(new_size, m->UsedSize()); 733 1.1 mrg // If realloc() races with free(), we may start copying freed memory. 734 1.1 mrg // However, we will report racy double-free later anyway. 735 1.1 mrg REAL(memcpy)(new_ptr, old_ptr, memcpy_size); 736 1.1 mrg Deallocate(old_ptr, 0, 0, stack, FROM_MALLOC); 737 1.1 mrg } 738 1.1 mrg return new_ptr; 739 1.1 mrg } 740 1.1 mrg 741 1.1 mrg void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { 742 1.1 mrg if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { 743 1.1 mrg if (AllocatorMayReturnNull()) 744 1.1 mrg return nullptr; 745 1.1 mrg ReportCallocOverflow(nmemb, size, stack); 746 1.1 mrg } 747 1.1 mrg void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false); 748 1.1 mrg // If the memory comes from the secondary allocator no need to clear it 749 1.1 mrg // as it comes directly from mmap. 750 1.1 mrg if (ptr && allocator.FromPrimary(ptr)) 751 1.1 mrg REAL(memset)(ptr, 0, nmemb * size); 752 1.1 mrg return ptr; 753 1.1 mrg } 754 1.1 mrg 755 1.1 mrg void ReportInvalidFree(void *ptr, u8 chunk_state, BufferedStackTrace *stack) { 756 1.1 mrg if (chunk_state == CHUNK_QUARANTINE) 757 1.1 mrg ReportDoubleFree((uptr)ptr, stack); 758 1.1 mrg else 759 1.1 mrg ReportFreeNotMalloced((uptr)ptr, stack); 760 1.1 mrg } 761 1.1 mrg 762 1.1 mrg void CommitBack(AsanThreadLocalMallocStorage *ms, BufferedStackTrace *stack) { 763 1.1 mrg AllocatorCache *ac = GetAllocatorCache(ms); 764 1.1 mrg quarantine.Drain(GetQuarantineCache(ms), QuarantineCallback(ac, stack)); 765 1.1 mrg allocator.SwallowCache(ac); 766 1.1 mrg } 767 1.1 mrg 768 1.1 mrg // -------------------------- Chunk lookup ---------------------- 769 1.1 mrg 770 1.1 mrg // Assumes alloc_beg == allocator.GetBlockBegin(alloc_beg). 771 1.1 mrg // Returns nullptr if AsanChunk is not yet initialized just after 772 1.1 mrg // get_allocator().Allocate(), or is being destroyed just before 773 1.1 mrg // get_allocator().Deallocate(). 774 1.1 mrg AsanChunk *GetAsanChunk(void *alloc_beg) { 775 1.1 mrg if (!alloc_beg) 776 1.1 mrg return nullptr; 777 1.1 mrg AsanChunk *p = reinterpret_cast<LargeChunkHeader *>(alloc_beg)->Get(); 778 1.1 mrg if (!p) { 779 1.1 mrg if (!allocator.FromPrimary(alloc_beg)) 780 1.1 mrg return nullptr; 781 1.1 mrg p = reinterpret_cast<AsanChunk *>(alloc_beg); 782 1.1 mrg } 783 1.1 mrg u8 state = atomic_load(&p->chunk_state, memory_order_relaxed); 784 1.1 mrg // It does not guaranty that Chunk is initialized, but it's 785 1.1 mrg // definitely not for any other value. 786 1.1 mrg if (state == CHUNK_ALLOCATED || state == CHUNK_QUARANTINE) 787 1.1 mrg return p; 788 1.1 mrg return nullptr; 789 1.1 mrg } 790 1.1 mrg 791 1.1 mrg AsanChunk *GetAsanChunkByAddr(uptr p) { 792 1.1 mrg void *alloc_beg = allocator.GetBlockBegin(reinterpret_cast<void *>(p)); 793 1.1 mrg return GetAsanChunk(alloc_beg); 794 1.1 mrg } 795 1.1 mrg 796 1.1 mrg // Allocator must be locked when this function is called. 797 1.1 mrg AsanChunk *GetAsanChunkByAddrFastLocked(uptr p) { 798 1.1 mrg void *alloc_beg = 799 1.1 mrg allocator.GetBlockBeginFastLocked(reinterpret_cast<void *>(p)); 800 1.1 mrg return GetAsanChunk(alloc_beg); 801 1.1 mrg } 802 1.1 mrg 803 1.1 mrg uptr AllocationSize(uptr p) { 804 1.1 mrg AsanChunk *m = GetAsanChunkByAddr(p); 805 1.1 mrg if (!m) return 0; 806 1.1 mrg if (atomic_load(&m->chunk_state, memory_order_acquire) != CHUNK_ALLOCATED) 807 1.1 mrg return 0; 808 1.1 mrg if (m->Beg() != p) return 0; 809 1.1 mrg return m->UsedSize(); 810 1.1 mrg } 811 1.1 mrg 812 1.1 mrg AsanChunkView FindHeapChunkByAddress(uptr addr) { 813 1.1 mrg AsanChunk *m1 = GetAsanChunkByAddr(addr); 814 1.1 mrg sptr offset = 0; 815 1.1 mrg if (!m1 || AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) { 816 1.1 mrg // The address is in the chunk's left redzone, so maybe it is actually 817 1.1 mrg // a right buffer overflow from the other chunk to the left. 818 1.1 mrg // Search a bit to the left to see if there is another chunk. 819 1.1 mrg AsanChunk *m2 = nullptr; 820 1.1 mrg for (uptr l = 1; l < GetPageSizeCached(); l++) { 821 1.1 mrg m2 = GetAsanChunkByAddr(addr - l); 822 1.1 mrg if (m2 == m1) continue; // Still the same chunk. 823 1.1 mrg break; 824 1.1 mrg } 825 1.1 mrg if (m2 && AsanChunkView(m2).AddrIsAtRight(addr, 1, &offset)) 826 1.1 mrg m1 = ChooseChunk(addr, m2, m1); 827 1.1 mrg } 828 1.1 mrg return AsanChunkView(m1); 829 1.1 mrg } 830 1.1 mrg 831 1.1 mrg void Purge(BufferedStackTrace *stack) { 832 1.1 mrg AsanThread *t = GetCurrentThread(); 833 1.1 mrg if (t) { 834 1.1 mrg AsanThreadLocalMallocStorage *ms = &t->malloc_storage(); 835 1.1 mrg quarantine.DrainAndRecycle(GetQuarantineCache(ms), 836 1.1 mrg QuarantineCallback(GetAllocatorCache(ms), 837 1.1 mrg stack)); 838 1.1 mrg } 839 1.1 mrg { 840 1.1 mrg SpinMutexLock l(&fallback_mutex); 841 1.1 mrg quarantine.DrainAndRecycle(&fallback_quarantine_cache, 842 1.1 mrg QuarantineCallback(&fallback_allocator_cache, 843 1.1 mrg stack)); 844 1.1 mrg } 845 1.1 mrg 846 1.1 mrg allocator.ForceReleaseToOS(); 847 1.1 mrg } 848 1.1 mrg 849 1.1 mrg void PrintStats() { 850 1.1 mrg allocator.PrintStats(); 851 1.1 mrg quarantine.PrintStats(); 852 1.1 mrg } 853 1.1 mrg 854 1.1 mrg void ForceLock() ACQUIRE(fallback_mutex) { 855 1.1 mrg allocator.ForceLock(); 856 1.1 mrg fallback_mutex.Lock(); 857 1.1 mrg } 858 1.1 mrg 859 1.1 mrg void ForceUnlock() RELEASE(fallback_mutex) { 860 1.1 mrg fallback_mutex.Unlock(); 861 1.1 mrg allocator.ForceUnlock(); 862 1.1 mrg } 863 1.1 mrg }; 864 1.1 mrg 865 1.1 mrg static Allocator instance(LINKER_INITIALIZED); 866 1.1 mrg 867 1.1 mrg static AsanAllocator &get_allocator() { 868 1.1 mrg return instance.allocator; 869 1.1 mrg } 870 1.1 mrg 871 1.1 mrg bool AsanChunkView::IsValid() const { 872 1.1 mrg return chunk_ && atomic_load(&chunk_->chunk_state, memory_order_relaxed) != 873 1.1 mrg CHUNK_INVALID; 874 1.1 mrg } 875 1.1 mrg bool AsanChunkView::IsAllocated() const { 876 1.1 mrg return chunk_ && atomic_load(&chunk_->chunk_state, memory_order_relaxed) == 877 1.1 mrg CHUNK_ALLOCATED; 878 1.1 mrg } 879 1.1 mrg bool AsanChunkView::IsQuarantined() const { 880 1.1 mrg return chunk_ && atomic_load(&chunk_->chunk_state, memory_order_relaxed) == 881 1.1 mrg CHUNK_QUARANTINE; 882 1.1 mrg } 883 1.1 mrg uptr AsanChunkView::Beg() const { return chunk_->Beg(); } 884 1.1 mrg uptr AsanChunkView::End() const { return Beg() + UsedSize(); } 885 1.1 mrg uptr AsanChunkView::UsedSize() const { return chunk_->UsedSize(); } 886 1.1 mrg u32 AsanChunkView::UserRequestedAlignment() const { 887 1.1 mrg return Allocator::ComputeUserAlignment(chunk_->user_requested_alignment_log); 888 1.1 mrg } 889 1.1 mrg 890 1.1 mrg uptr AsanChunkView::AllocTid() const { 891 1.1 mrg u32 tid = 0; 892 1.1 mrg u32 stack = 0; 893 1.1 mrg chunk_->GetAllocContext(tid, stack); 894 1.1 mrg return tid; 895 1.1 mrg } 896 1.1 mrg 897 1.1 mrg uptr AsanChunkView::FreeTid() const { 898 1.1 mrg if (!IsQuarantined()) 899 1.1 mrg return kInvalidTid; 900 1.1 mrg u32 tid = 0; 901 1.1 mrg u32 stack = 0; 902 1.1 mrg chunk_->GetFreeContext(tid, stack); 903 1.1 mrg return tid; 904 1.1 mrg } 905 1.1 mrg 906 1.1 mrg AllocType AsanChunkView::GetAllocType() const { 907 1.1 mrg return (AllocType)chunk_->alloc_type; 908 1.1 mrg } 909 1.1 mrg 910 1.1 mrg u32 AsanChunkView::GetAllocStackId() const { 911 1.1 mrg u32 tid = 0; 912 1.1 mrg u32 stack = 0; 913 1.1 mrg chunk_->GetAllocContext(tid, stack); 914 1.1 mrg return stack; 915 1.1 mrg } 916 1.1 mrg 917 1.1 mrg u32 AsanChunkView::GetFreeStackId() const { 918 1.1 mrg if (!IsQuarantined()) 919 1.1 mrg return 0; 920 1.1 mrg u32 tid = 0; 921 1.1 mrg u32 stack = 0; 922 1.1 mrg chunk_->GetFreeContext(tid, stack); 923 1.1 mrg return stack; 924 1.1 mrg } 925 1.1 mrg 926 1.1 mrg void InitializeAllocator(const AllocatorOptions &options) { 927 1.1 mrg instance.InitLinkerInitialized(options); 928 1.1 mrg } 929 1.1 mrg 930 1.1 mrg void ReInitializeAllocator(const AllocatorOptions &options) { 931 1.1 mrg instance.ReInitialize(options); 932 1.1 mrg } 933 1.1 mrg 934 1.1 mrg void GetAllocatorOptions(AllocatorOptions *options) { 935 1.1 mrg instance.GetOptions(options); 936 1.1 mrg } 937 1.1 mrg 938 1.1 mrg AsanChunkView FindHeapChunkByAddress(uptr addr) { 939 1.1 mrg return instance.FindHeapChunkByAddress(addr); 940 1.1 mrg } 941 1.1 mrg AsanChunkView FindHeapChunkByAllocBeg(uptr addr) { 942 1.1 mrg return AsanChunkView(instance.GetAsanChunk(reinterpret_cast<void*>(addr))); 943 1.1 mrg } 944 1.1 mrg 945 1.1 mrg void AsanThreadLocalMallocStorage::CommitBack() { 946 1.1 mrg GET_STACK_TRACE_MALLOC; 947 1.1 mrg instance.CommitBack(this, &stack); 948 1.1 mrg } 949 1.1 mrg 950 1.1 mrg void PrintInternalAllocatorStats() { 951 1.1 mrg instance.PrintStats(); 952 1.1 mrg } 953 1.1 mrg 954 1.1 mrg void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) { 955 1.1 mrg instance.Deallocate(ptr, 0, 0, stack, alloc_type); 956 1.1 mrg } 957 1.1 mrg 958 1.1 mrg void asan_delete(void *ptr, uptr size, uptr alignment, 959 1.1 mrg BufferedStackTrace *stack, AllocType alloc_type) { 960 1.1 mrg instance.Deallocate(ptr, size, alignment, stack, alloc_type); 961 1.1 mrg } 962 1.1 mrg 963 1.1 mrg void *asan_malloc(uptr size, BufferedStackTrace *stack) { 964 1.1 mrg return SetErrnoOnNull(instance.Allocate(size, 8, stack, FROM_MALLOC, true)); 965 1.1 mrg } 966 1.1 mrg 967 1.1 mrg void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) { 968 1.1 mrg return SetErrnoOnNull(instance.Calloc(nmemb, size, stack)); 969 1.1 mrg } 970 1.1 mrg 971 1.1 mrg void *asan_reallocarray(void *p, uptr nmemb, uptr size, 972 1.1 mrg BufferedStackTrace *stack) { 973 1.1 mrg if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) { 974 1.1 mrg errno = errno_ENOMEM; 975 1.1 mrg if (AllocatorMayReturnNull()) 976 1.1 mrg return nullptr; 977 1.1 mrg ReportReallocArrayOverflow(nmemb, size, stack); 978 1.1 mrg } 979 1.1 mrg return asan_realloc(p, nmemb * size, stack); 980 1.1 mrg } 981 1.1 mrg 982 1.1 mrg void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) { 983 1.1 mrg if (!p) 984 1.1 mrg return SetErrnoOnNull(instance.Allocate(size, 8, stack, FROM_MALLOC, true)); 985 1.1 mrg if (size == 0) { 986 1.1 mrg if (flags()->allocator_frees_and_returns_null_on_realloc_zero) { 987 1.1 mrg instance.Deallocate(p, 0, 0, stack, FROM_MALLOC); 988 1.1 mrg return nullptr; 989 1.1 mrg } 990 1.1 mrg // Allocate a size of 1 if we shouldn't free() on Realloc to 0 991 1.1 mrg size = 1; 992 1.1 mrg } 993 1.1 mrg return SetErrnoOnNull(instance.Reallocate(p, size, stack)); 994 1.1 mrg } 995 1.1 mrg 996 1.1 mrg void *asan_valloc(uptr size, BufferedStackTrace *stack) { 997 1.1 mrg return SetErrnoOnNull( 998 1.1 mrg instance.Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true)); 999 1.1 mrg } 1000 1.1 mrg 1001 1.1 mrg void *asan_pvalloc(uptr size, BufferedStackTrace *stack) { 1002 1.1 mrg uptr PageSize = GetPageSizeCached(); 1003 1.1 mrg if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) { 1004 1.1 mrg errno = errno_ENOMEM; 1005 1.1 mrg if (AllocatorMayReturnNull()) 1006 1.1 mrg return nullptr; 1007 1.1 mrg ReportPvallocOverflow(size, stack); 1008 1.1 mrg } 1009 1.1 mrg // pvalloc(0) should allocate one page. 1010 1.1 mrg size = size ? RoundUpTo(size, PageSize) : PageSize; 1011 1.1 mrg return SetErrnoOnNull( 1012 1.1 mrg instance.Allocate(size, PageSize, stack, FROM_MALLOC, true)); 1013 1.1 mrg } 1014 1.1 mrg 1015 1.1 mrg void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack, 1016 1.1 mrg AllocType alloc_type) { 1017 1.1 mrg if (UNLIKELY(!IsPowerOfTwo(alignment))) { 1018 1.1 mrg errno = errno_EINVAL; 1019 1.1 mrg if (AllocatorMayReturnNull()) 1020 1.1 mrg return nullptr; 1021 1.1 mrg ReportInvalidAllocationAlignment(alignment, stack); 1022 1.1 mrg } 1023 1.1 mrg return SetErrnoOnNull( 1024 1.1 mrg instance.Allocate(size, alignment, stack, alloc_type, true)); 1025 1.1 mrg } 1026 1.1 mrg 1027 1.1 mrg void *asan_aligned_alloc(uptr alignment, uptr size, BufferedStackTrace *stack) { 1028 1.1 mrg if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) { 1029 1.1 mrg errno = errno_EINVAL; 1030 1.1 mrg if (AllocatorMayReturnNull()) 1031 1.1 mrg return nullptr; 1032 1.1 mrg ReportInvalidAlignedAllocAlignment(size, alignment, stack); 1033 1.1 mrg } 1034 1.1 mrg return SetErrnoOnNull( 1035 1.1 mrg instance.Allocate(size, alignment, stack, FROM_MALLOC, true)); 1036 1.1 mrg } 1037 1.1 mrg 1038 1.1 mrg int asan_posix_memalign(void **memptr, uptr alignment, uptr size, 1039 1.1 mrg BufferedStackTrace *stack) { 1040 1.1 mrg if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) { 1041 1.1 mrg if (AllocatorMayReturnNull()) 1042 1.1 mrg return errno_EINVAL; 1043 1.1 mrg ReportInvalidPosixMemalignAlignment(alignment, stack); 1044 1.1 mrg } 1045 1.1 mrg void *ptr = instance.Allocate(size, alignment, stack, FROM_MALLOC, true); 1046 1.1 mrg if (UNLIKELY(!ptr)) 1047 1.1 mrg // OOM error is already taken care of by Allocate. 1048 1.1 mrg return errno_ENOMEM; 1049 1.1 mrg CHECK(IsAligned((uptr)ptr, alignment)); 1050 1.1 mrg *memptr = ptr; 1051 1.1 mrg return 0; 1052 1.1 mrg } 1053 1.1 mrg 1054 1.1 mrg uptr asan_malloc_usable_size(const void *ptr, uptr pc, uptr bp) { 1055 1.1 mrg if (!ptr) return 0; 1056 1.1 mrg uptr usable_size = instance.AllocationSize(reinterpret_cast<uptr>(ptr)); 1057 1.1 mrg if (flags()->check_malloc_usable_size && (usable_size == 0)) { 1058 1.1 mrg GET_STACK_TRACE_FATAL(pc, bp); 1059 1.1 mrg ReportMallocUsableSizeNotOwned((uptr)ptr, &stack); 1060 1.1 mrg } 1061 1.1 mrg return usable_size; 1062 1.1 mrg } 1063 1.1 mrg 1064 1.1 mrg uptr asan_mz_size(const void *ptr) { 1065 1.1 mrg return instance.AllocationSize(reinterpret_cast<uptr>(ptr)); 1066 1.1 mrg } 1067 1.1 mrg 1068 1.1 mrg void asan_mz_force_lock() NO_THREAD_SAFETY_ANALYSIS { instance.ForceLock(); } 1069 1.1 mrg 1070 1.1 mrg void asan_mz_force_unlock() NO_THREAD_SAFETY_ANALYSIS { 1071 1.1 mrg instance.ForceUnlock(); 1072 1.1 mrg } 1073 1.1 mrg 1074 1.1 mrg void AsanSoftRssLimitExceededCallback(bool limit_exceeded) { 1075 1.1 mrg instance.SetRssLimitExceeded(limit_exceeded); 1076 1.1 mrg } 1077 1.1 mrg 1078 1.1 mrg } // namespace __asan 1079 1.1 mrg 1080 1.1 mrg // --- Implementation of LSan-specific functions --- {{{1 1081 1.1 mrg namespace __lsan { 1082 1.1 mrg void LockAllocator() { 1083 1.1 mrg __asan::get_allocator().ForceLock(); 1084 1.1 mrg } 1085 1.1 mrg 1086 1.1 mrg void UnlockAllocator() { 1087 1.1 mrg __asan::get_allocator().ForceUnlock(); 1088 1.1 mrg } 1089 1.1 mrg 1090 1.1 mrg void GetAllocatorGlobalRange(uptr *begin, uptr *end) { 1091 1.1 mrg *begin = (uptr)&__asan::get_allocator(); 1092 1.1 mrg *end = *begin + sizeof(__asan::get_allocator()); 1093 1.1 mrg } 1094 1.1 mrg 1095 1.1 mrg uptr PointsIntoChunk(void *p) { 1096 1.1 mrg uptr addr = reinterpret_cast<uptr>(p); 1097 1.1 mrg __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(addr); 1098 1.1 mrg if (!m || atomic_load(&m->chunk_state, memory_order_acquire) != 1099 1.1 mrg __asan::CHUNK_ALLOCATED) 1100 1.1 mrg return 0; 1101 1.1 mrg uptr chunk = m->Beg(); 1102 1.1 mrg if (m->AddrIsInside(addr)) 1103 1.1 mrg return chunk; 1104 1.1 mrg if (IsSpecialCaseOfOperatorNew0(chunk, m->UsedSize(), addr)) 1105 1.1 mrg return chunk; 1106 1.1 mrg return 0; 1107 1.1 mrg } 1108 1.1 mrg 1109 1.1 mrg uptr GetUserBegin(uptr chunk) { 1110 1.1 mrg __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(chunk); 1111 1.1 mrg return m ? m->Beg() : 0; 1112 1.1 mrg } 1113 1.1 mrg 1114 1.1 mrg LsanMetadata::LsanMetadata(uptr chunk) { 1115 1.1 mrg metadata_ = chunk ? reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize) 1116 1.1 mrg : nullptr; 1117 1.1 mrg } 1118 1.1 mrg 1119 1.1 mrg bool LsanMetadata::allocated() const { 1120 1.1 mrg if (!metadata_) 1121 1.1 mrg return false; 1122 1.1 mrg __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); 1123 1.1 mrg return atomic_load(&m->chunk_state, memory_order_relaxed) == 1124 1.1 mrg __asan::CHUNK_ALLOCATED; 1125 1.1 mrg } 1126 1.1 mrg 1127 1.1 mrg ChunkTag LsanMetadata::tag() const { 1128 1.1 mrg __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); 1129 1.1 mrg return static_cast<ChunkTag>(m->lsan_tag); 1130 1.1 mrg } 1131 1.1 mrg 1132 1.1 mrg void LsanMetadata::set_tag(ChunkTag value) { 1133 1.1 mrg __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); 1134 1.1 mrg m->lsan_tag = value; 1135 1.1 mrg } 1136 1.1 mrg 1137 1.1 mrg uptr LsanMetadata::requested_size() const { 1138 1.1 mrg __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); 1139 1.1 mrg return m->UsedSize(); 1140 1.1 mrg } 1141 1.1 mrg 1142 1.1 mrg u32 LsanMetadata::stack_trace_id() const { 1143 1.1 mrg __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_); 1144 1.1 mrg u32 tid = 0; 1145 1.1 mrg u32 stack = 0; 1146 1.1 mrg m->GetAllocContext(tid, stack); 1147 1.1 mrg return stack; 1148 1.1 mrg } 1149 1.1 mrg 1150 1.1 mrg void ForEachChunk(ForEachChunkCallback callback, void *arg) { 1151 1.1 mrg __asan::get_allocator().ForEachChunk(callback, arg); 1152 1.1 mrg } 1153 1.1 mrg 1154 1.1 mrg IgnoreObjectResult IgnoreObjectLocked(const void *p) { 1155 1.1 mrg uptr addr = reinterpret_cast<uptr>(p); 1156 1.1 mrg __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddr(addr); 1157 1.1 mrg if (!m || 1158 1.1 mrg (atomic_load(&m->chunk_state, memory_order_acquire) != 1159 1.1 mrg __asan::CHUNK_ALLOCATED) || 1160 1.1 mrg !m->AddrIsInside(addr)) { 1161 1.1 mrg return kIgnoreObjectInvalid; 1162 1.1 mrg } 1163 1.1 mrg if (m->lsan_tag == kIgnored) 1164 1.1 mrg return kIgnoreObjectAlreadyIgnored; 1165 1.1 mrg m->lsan_tag = __lsan::kIgnored; 1166 1.1 mrg return kIgnoreObjectSuccess; 1167 1.1 mrg } 1168 1.1 mrg 1169 1.1 mrg void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) { 1170 1.1 mrg // Look for the arg pointer of threads that have been created or are running. 1171 1.1 mrg // This is necessary to prevent false positive leaks due to the AsanThread 1172 1.1 mrg // holding the only live reference to a heap object. This can happen because 1173 1.1 mrg // the `pthread_create()` interceptor doesn't wait for the child thread to 1174 1.1 mrg // start before returning and thus loosing the the only live reference to the 1175 1.1 mrg // heap object on the stack. 1176 1.1 mrg 1177 1.1 mrg __asan::AsanThreadContext *atctx = 1178 1.1 mrg reinterpret_cast<__asan::AsanThreadContext *>(tctx); 1179 1.1 mrg __asan::AsanThread *asan_thread = atctx->thread; 1180 1.1 mrg 1181 1.1 mrg // Note ThreadStatusRunning is required because there is a small window where 1182 1.1 mrg // the thread status switches to `ThreadStatusRunning` but the `arg` pointer 1183 1.1 mrg // still isn't on the stack yet. 1184 1.1 mrg if (atctx->status != ThreadStatusCreated && 1185 1.1 mrg atctx->status != ThreadStatusRunning) 1186 1.1 mrg return; 1187 1.1 mrg 1188 1.1 mrg uptr thread_arg = reinterpret_cast<uptr>(asan_thread->get_arg()); 1189 1.1 mrg if (!thread_arg) 1190 1.1 mrg return; 1191 1.1 mrg 1192 1.1 mrg auto ptrsVec = reinterpret_cast<InternalMmapVector<uptr> *>(ptrs); 1193 1.1 mrg ptrsVec->push_back(thread_arg); 1194 1.1 mrg } 1195 1.1 mrg 1196 1.1 mrg } // namespace __lsan 1197 1.1 mrg 1198 1.1 mrg // ---------------------- Interface ---------------- {{{1 1199 1.1 mrg using namespace __asan; 1200 1.1 mrg 1201 1.1 mrg // ASan allocator doesn't reserve extra bytes, so normally we would 1202 1.1 mrg // just return "size". We don't want to expose our redzone sizes, etc here. 1203 1.1 mrg uptr __sanitizer_get_estimated_allocated_size(uptr size) { 1204 1.1 mrg return size; 1205 1.1 mrg } 1206 1.1 mrg 1207 1.1 mrg int __sanitizer_get_ownership(const void *p) { 1208 1.1 mrg uptr ptr = reinterpret_cast<uptr>(p); 1209 1.1 mrg return instance.AllocationSize(ptr) > 0; 1210 1.1 mrg } 1211 1.1 mrg 1212 1.1 mrg uptr __sanitizer_get_allocated_size(const void *p) { 1213 1.1 mrg if (!p) return 0; 1214 1.1 mrg uptr ptr = reinterpret_cast<uptr>(p); 1215 1.1 mrg uptr allocated_size = instance.AllocationSize(ptr); 1216 1.1 mrg // Die if p is not malloced or if it is already freed. 1217 1.1 mrg if (allocated_size == 0) { 1218 1.1 mrg GET_STACK_TRACE_FATAL_HERE; 1219 1.1 mrg ReportSanitizerGetAllocatedSizeNotOwned(ptr, &stack); 1220 1.1 mrg } 1221 1.1 mrg return allocated_size; 1222 1.1 mrg } 1223 1.1 mrg 1224 1.1 mrg void __sanitizer_purge_allocator() { 1225 1.1 mrg GET_STACK_TRACE_MALLOC; 1226 1.1 mrg instance.Purge(&stack); 1227 1.1 mrg } 1228 1.1 mrg 1229 1.1 mrg int __asan_update_allocation_context(void* addr) { 1230 1.1 mrg GET_STACK_TRACE_MALLOC; 1231 1.1 mrg return instance.UpdateAllocationStack((uptr)addr, &stack); 1232 1.1 mrg } 1233 1.1 mrg 1234 1.1 mrg #if !SANITIZER_SUPPORTS_WEAK_HOOKS 1235 1.1 mrg // Provide default (no-op) implementation of malloc hooks. 1236 1.1 mrg SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, 1237 1.1 mrg void *ptr, uptr size) { 1238 1.1 mrg (void)ptr; 1239 1.1 mrg (void)size; 1240 1.1 mrg } 1241 1.1 mrg 1242 1.1 mrg SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) { 1243 1.1 mrg (void)ptr; 1244 1.1 mrg } 1245 1.1 mrg #endif 1246