From 91c28bbe74f24e0e84edf84daae7659c11e7afd6 Mon Sep 17 00:00:00 2001 From: Vitaly Buka Date: Wed, 9 Sep 2020 16:17:37 -0700 Subject: [PATCH] [Asan] Return nullptr for invalid chunks CHUNK_ALLOCATED. CHUNK_QUARANTINE are only states which make AsanChunk useful for GetAsanChunk callers. In either case member of AsanChunk are not useful. Fix few cases which didn't expect nullptr. Most of the callers are already expects nullptr. Reviewed By: morehouse Differential Revision: https://reviews.llvm.org/D87135 --- compiler-rt/lib/asan/asan_allocator.cpp | 38 +++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/compiler-rt/lib/asan/asan_allocator.cpp b/compiler-rt/lib/asan/asan_allocator.cpp index 64796f7..f7e238d 100644 --- a/compiler-rt/lib/asan/asan_allocator.cpp +++ b/compiler-rt/lib/asan/asan_allocator.cpp @@ -302,9 +302,9 @@ struct Allocator { // This could be a user-facing chunk (with redzones), or some internal // housekeeping chunk, like TransferBatch. Start by assuming the former. AsanChunk *ac = GetAsanChunk((void *)chunk); - uptr allocated_size = allocator.GetActuallyAllocatedSize((void *)ac); - if (atomic_load(&ac->chunk_state, memory_order_acquire) == - CHUNK_ALLOCATED) { + uptr allocated_size = allocator.GetActuallyAllocatedSize((void *)chunk); + if (ac && atomic_load(&ac->chunk_state, memory_order_acquire) == + CHUNK_ALLOCATED) { uptr beg = ac->Beg(); uptr end = ac->Beg() + ac->UsedSize(true); uptr chunk_end = chunk + allocated_size; @@ -385,6 +385,10 @@ struct Allocator { // We have an address between two chunks, and we want to report just one. AsanChunk *ChooseChunk(uptr addr, AsanChunk *left_chunk, AsanChunk *right_chunk) { + if (!left_chunk) + return right_chunk; + if (!right_chunk) + return left_chunk; // Prefer an allocated chunk over freed chunk and freed chunk // over available chunk. u8 left_state = atomic_load(&left_chunk->chunk_state, memory_order_relaxed); @@ -737,18 +741,25 @@ struct Allocator { AsanChunk *GetAsanChunk(void *alloc_beg) { if (!alloc_beg) return nullptr; + AsanChunk *p = nullptr; if (!allocator.FromPrimary(alloc_beg)) { uptr *meta = reinterpret_cast(allocator.GetMetaData(alloc_beg)); - AsanChunk *m = reinterpret_cast(meta[1]); - return m; + p = reinterpret_cast(meta[1]); + } else { + uptr *alloc_magic = reinterpret_cast(alloc_beg); + if (alloc_magic[0] == kAllocBegMagic) + p = reinterpret_cast(alloc_magic[1]); + else + p = reinterpret_cast(alloc_beg); } - uptr *alloc_magic = reinterpret_cast(alloc_beg); - if (alloc_magic[0] == kAllocBegMagic) - return reinterpret_cast(alloc_magic[1]); - // FIXME: This is either valid small chunk with tiny redzone or invalid - // chunk which is beeing allocated/deallocated. The latter case should - // return nullptr like secondary allocator does. - return reinterpret_cast(alloc_beg); + if (!p) + return nullptr; + u8 state = atomic_load(&p->chunk_state, memory_order_relaxed); + // It does not guaranty that Chunk is initialized, but it's + // definitely not for any other value. + if (state == CHUNK_ALLOCATED || state == CHUNK_QUARANTINE) + return p; + return nullptr; } AsanChunk *GetAsanChunkByAddr(uptr p) { @@ -774,9 +785,8 @@ struct Allocator { AsanChunkView FindHeapChunkByAddress(uptr addr) { AsanChunk *m1 = GetAsanChunkByAddr(addr); - if (!m1) return AsanChunkView(m1); sptr offset = 0; - if (AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) { + if (!m1 || AsanChunkView(m1).AddrIsAtLeft(addr, 1, &offset)) { // The address is in the chunk's left redzone, so maybe it is actually // a right buffer overflow from the other chunk to the left. // Search a bit to the left to see if there is another chunk. -- 2.7.4