[asan] asan_allocator2: improve FindHeapChunkByAddress to find memory chunks to the...
authorKostya Serebryany <kcc@google.com>
Wed, 19 Dec 2012 08:32:50 +0000 (08:32 +0000)
committerKostya Serebryany <kcc@google.com>
Wed, 19 Dec 2012 08:32:50 +0000 (08:32 +0000)
llvm-svn: 170511

compiler-rt/lib/asan/asan_allocator2.cc
compiler-rt/lib/sanitizer_common/sanitizer_allocator.h

index 8153a1d..5dac665 100644 (file)
@@ -378,8 +378,44 @@ static uptr AllocationSize(uptr p) {
   return m->UsedSize();
 }
 
-AsanChunkView FindHeapChunkByAddress(uptr address) {
-  return AsanChunkView(GetAsanChunkByAddr(address));
+// We have an address between two chunks, and we want to report just one.
+AsanChunk *ChooseChunk(uptr addr,
+                       AsanChunk *left_chunk, AsanChunk *right_chunk) {
+  // Prefer an allocated chunk or a chunk from quarantine.
+  if (left_chunk->chunk_state == CHUNK_AVAILABLE &&
+      right_chunk->chunk_state != CHUNK_AVAILABLE)
+    return right_chunk;
+  if (right_chunk->chunk_state == CHUNK_AVAILABLE &&
+      left_chunk->chunk_state != CHUNK_AVAILABLE)
+    return left_chunk;
+  // Choose based on offset.
+  uptr l_offset = 0, r_offset = 0;
+  CHECK(AsanChunkView(left_chunk).AddrIsAtRight(addr, 1, &l_offset));
+  CHECK(AsanChunkView(right_chunk).AddrIsAtLeft(addr, 1, &r_offset));
+  if (l_offset < r_offset)
+    return left_chunk;
+  return right_chunk;
+}
+
+AsanChunkView FindHeapChunkByAddress(uptr addr) {
+  AsanChunk *m1 = GetAsanChunkByAddr(addr);
+  if (!m1) return AsanChunkView(m1);
+  uptr offset = 0;
+  if (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.
+    AsanChunk *m2 = 0;
+    for (uptr l = 1; l < GetPageSizeCached(); l++) {
+      m2 = GetAsanChunkByAddr(addr - l);
+      if (m2 == m1) continue;  // Still the same chunk.
+      Printf("m1 %p m2 %p l %zd\n", m1, m2, l);
+      break;
+    }
+    if (m2 && AsanChunkView(m2).AddrIsAtRight(addr, 1, &offset))
+      m1 = ChooseChunk(addr, m2, m1);
+  }
+  return AsanChunkView(m1);
 }
 
 void AsanThreadLocalMallocStorage::CommitBack() {
index 87a7fc1..5376875 100644 (file)
@@ -207,13 +207,16 @@ class SizeClassAllocator64 {
     return (reinterpret_cast<uptr>(p) / kRegionSize) % kNumClasses;
   }
 
-  static void *GetBlockBegin(void *p) {
+  void *GetBlockBegin(void *p) {
     uptr class_id = GetSizeClass(p);
     uptr size = SizeClassMap::Size(class_id);
     uptr chunk_idx = GetChunkIdx((uptr)p, size);
     uptr reg_beg = (uptr)p & ~(kRegionSize - 1);
     uptr begin = reg_beg + chunk_idx * size;
-    return reinterpret_cast<void*>(begin);
+    RegionInfo *region = GetRegionInfo(class_id);
+    if (region->allocated_user >= (chunk_idx + 1) * size)
+      return reinterpret_cast<void*>(begin);
+    return 0;
   }
 
   static uptr GetActuallyAllocatedSize(void *p) {