[compiler-rt] 3f7c3e8 - [Asan] Fix __asan_update_allocation_context

Vitaly Buka via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 10 19:59:54 PDT 2020


Author: Vitaly Buka
Date: 2020-09-10T19:59:43-07:00
New Revision: 3f7c3e84ad69f1ffa767b1b7ce3aa36de6c30f87

URL: https://github.com/llvm/llvm-project/commit/3f7c3e84ad69f1ffa767b1b7ce3aa36de6c30f87
DIFF: https://github.com/llvm/llvm-project/commit/3f7c3e84ad69f1ffa767b1b7ce3aa36de6c30f87.diff

LOG: [Asan] Fix __asan_update_allocation_context

Update both thread and stack.
Update thread and stack as atomic operation.
Keep all 32bit of TID as now we have enough bits.

Depends on D87135.

Reviewed By: morehouse

Differential Revision: https://reviews.llvm.org/D87217

Added: 
    

Modified: 
    compiler-rt/lib/asan/asan_allocator.cpp
    compiler-rt/lib/asan/asan_allocator.h
    compiler-rt/test/asan/TestCases/asan_update_allocation.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/asan/asan_allocator.cpp b/compiler-rt/lib/asan/asan_allocator.cpp
index f7e238d613e1..8cc7de3a9862 100644
--- a/compiler-rt/lib/asan/asan_allocator.cpp
+++ b/compiler-rt/lib/asan/asan_allocator.cpp
@@ -51,6 +51,22 @@ static u32 RZSize2Log(u32 rz_size) {
 
 static AsanAllocator &get_allocator();
 
+static void AtomicContextStore(volatile atomic_uint64_t *atomic_context,
+                               u32 tid, u32 stack) {
+  u64 context = tid;
+  context <<= 32;
+  context += stack;
+  atomic_store(atomic_context, context, memory_order_relaxed);
+}
+
+static void AtomicContextLoad(const volatile atomic_uint64_t *atomic_context,
+                              u32 &tid, u32 &stack) {
+  u64 context = atomic_load(atomic_context, memory_order_relaxed);
+  stack = context;
+  context >>= 32;
+  tid = context;
+}
+
 // The memory chunk allocated from the underlying allocator looks like this:
 // L L L L L L H H U U U U U U R R
 //   L -- left redzone words (0 or more bytes)
@@ -70,12 +86,14 @@ static AsanAllocator &get_allocator();
 //   B -- address of ChunkHeader pointing to the first 'H'
 static const uptr kAllocBegMagic = 0xCC6E96B9;
 
-struct ChunkHeader {
+class ChunkHeader {
+ public:
   atomic_uint8_t chunk_state;
   u8 from_memalign : 1;
   u8 alloc_type : 2;
   u8 rz_log : 3;
   u8 lsan_tag : 2;
+
   // This field is used for small sizes. For large sizes it is equal to
   // SizeClassMap::kMaxSize and the actual size is stored in the
   // SecondaryAllocator's metadata.
@@ -83,14 +101,31 @@ struct ChunkHeader {
   // align < 8 -> 0
   // else      -> log2(min(align, 512)) - 2
   u32 user_requested_alignment_log : 3;
-  u32 alloc_tid;
-  atomic_uint32_t alloc_context_id;
+
+ private:
+  atomic_uint64_t alloc_context_id;
+
+ public:
+  void SetAllocContext(u32 tid, u32 stack) {
+    AtomicContextStore(&alloc_context_id, tid, stack);
+  }
+
+  void GetAllocContext(u32 &tid, u32 &stack) const {
+    AtomicContextLoad(&alloc_context_id, tid, stack);
+  }
 };
 
-struct ChunkBase : ChunkHeader {
-  // Header2, intersects with user memory.
-  u32 free_context_id;
-  u32 free_tid;
+class ChunkBase : public ChunkHeader {
+  atomic_uint64_t free_context_id;
+
+ public:
+  void SetFreeContext(u32 tid, u32 stack) {
+    AtomicContextStore(&free_context_id, tid, stack);
+  }
+
+  void GetFreeContext(u32 &tid, u32 &stack) const {
+    AtomicContextLoad(&free_context_id, tid, stack);
+  }
 };
 
 static const uptr kChunkHeaderSize = sizeof(ChunkHeader);
@@ -109,7 +144,8 @@ enum {
   CHUNK_QUARANTINE = 3,
 };
 
-struct AsanChunk: ChunkBase {
+class AsanChunk : public ChunkBase {
+ public:
   uptr Beg() { return reinterpret_cast<uptr>(this) + kChunkHeaderSize; }
   uptr UsedSize(bool locked_version = false) {
     if (user_requested_size != SizeClassMap::kMaxSize)
@@ -144,8 +180,6 @@ struct QuarantineCallback {
       CHECK_EQ(old_chunk_state, CHUNK_QUARANTINE);
     }
 
-    CHECK_NE(m->alloc_tid, kInvalidTid);
-    CHECK_NE(m->free_tid, kInvalidTid);
     PoisonShadow(m->Beg(),
                  RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
                  kAsanHeapLeftRedzoneMagic);
@@ -419,8 +453,8 @@ struct Allocator {
     if (atomic_load(&m->chunk_state, memory_order_acquire) != CHUNK_ALLOCATED)
       return false;
     if (m->Beg() != addr) return false;
-    atomic_store(&m->alloc_context_id, StackDepotPut(*stack),
-                 memory_order_relaxed);
+    AsanThread *t = GetCurrentThread();
+    m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack));
     return true;
   }
 
@@ -515,9 +549,6 @@ struct Allocator {
     AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
     m->alloc_type = alloc_type;
     m->rz_log = rz_log;
-    u32 alloc_tid = t ? t->tid() : 0;
-    m->alloc_tid = alloc_tid;
-    CHECK_EQ(alloc_tid, m->alloc_tid);  // Does alloc_tid fit into the bitfield?
     m->from_memalign = user_beg != beg_plus_redzone;
     if (alloc_beg != chunk_beg) {
       CHECK_LE(alloc_beg + 2 * sizeof(uptr), chunk_beg);
@@ -537,8 +568,7 @@ struct Allocator {
     }
     m->user_requested_alignment_log = user_requested_alignment_log;
 
-    atomic_store(&m->alloc_context_id, StackDepotPut(*stack),
-                 memory_order_relaxed);
+    m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack));
 
     uptr size_rounded_down_to_granularity =
         RoundDownTo(size, SHADOW_GRANULARITY);
@@ -591,8 +621,7 @@ struct Allocator {
     }
     CHECK_EQ(CHUNK_ALLOCATED, old_chunk_state);
     // It was a user data.
-    m->free_tid = kInvalidTid;
-    m->free_context_id = 0;
+    m->SetFreeContext(kInvalidTid, 0);
     return true;
   }
 
@@ -602,8 +631,7 @@ struct Allocator {
     CHECK_EQ(atomic_load(&m->chunk_state, memory_order_relaxed),
              CHUNK_QUARANTINE);
     AsanThread *t = GetCurrentThread();
-    m->free_tid = t ? t->tid() : 0;
-    m->free_context_id = StackDepotPut(*stack);
+    m->SetFreeContext(t ? t->tid() : 0, StackDepotPut(*stack));
 
     Flags &fl = *flags();
     if (fl.max_free_fill_size > 0) {
@@ -860,10 +888,23 @@ uptr AsanChunkView::UsedSize() const { return chunk_->UsedSize(); }
 u32 AsanChunkView::UserRequestedAlignment() const {
   return Allocator::ComputeUserAlignment(chunk_->user_requested_alignment_log);
 }
-uptr AsanChunkView::AllocTid() const { return chunk_->alloc_tid; }
+
+uptr AsanChunkView::AllocTid() const {
+  u32 tid = 0;
+  u32 stack = 0;
+  chunk_->GetAllocContext(tid, stack);
+  return tid;
+}
+
 uptr AsanChunkView::FreeTid() const {
-  return IsQuarantined() ? chunk_->free_tid : kInvalidTid;
+  if (!IsQuarantined())
+    return kInvalidTid;
+  u32 tid = 0;
+  u32 stack = 0;
+  chunk_->GetFreeContext(tid, stack);
+  return tid;
 }
+
 AllocType AsanChunkView::GetAllocType() const {
   return (AllocType)chunk_->alloc_type;
 }
@@ -876,10 +917,19 @@ static StackTrace GetStackTraceFromId(u32 id) {
 }
 
 u32 AsanChunkView::GetAllocStackId() const {
-  return atomic_load(&chunk_->alloc_context_id, memory_order_relaxed);
+  u32 tid = 0;
+  u32 stack = 0;
+  chunk_->GetAllocContext(tid, stack);
+  return stack;
 }
+
 u32 AsanChunkView::GetFreeStackId() const {
-  return IsQuarantined() ? chunk_->free_context_id : 0;
+  if (!IsQuarantined())
+    return 0;
+  u32 tid = 0;
+  u32 stack = 0;
+  chunk_->GetFreeContext(tid, stack);
+  return stack;
 }
 
 StackTrace AsanChunkView::GetAllocStack() const {
@@ -1111,7 +1161,10 @@ uptr LsanMetadata::requested_size() const {
 
 u32 LsanMetadata::stack_trace_id() const {
   __asan::AsanChunk *m = reinterpret_cast<__asan::AsanChunk *>(metadata_);
-  return atomic_load(&m->alloc_context_id, memory_order_relaxed);
+  u32 tid = 0;
+  u32 stack = 0;
+  m->GetAllocContext(tid, stack);
+  return stack;
 }
 
 void ForEachChunk(ForEachChunkCallback callback, void *arg) {

diff  --git a/compiler-rt/lib/asan/asan_allocator.h b/compiler-rt/lib/asan/asan_allocator.h
index d60b97500a3c..612799f90964 100644
--- a/compiler-rt/lib/asan/asan_allocator.h
+++ b/compiler-rt/lib/asan/asan_allocator.h
@@ -28,7 +28,7 @@ enum AllocType {
   FROM_NEW_BR = 3   // Memory block came from operator new [ ]
 };
 
-struct AsanChunk;
+class AsanChunk;
 
 struct AllocatorOptions {
   u32 quarantine_size_mb;

diff  --git a/compiler-rt/test/asan/TestCases/asan_update_allocation.cpp b/compiler-rt/test/asan/TestCases/asan_update_allocation.cpp
index d703fe024aa0..065f793092f0 100644
--- a/compiler-rt/test/asan/TestCases/asan_update_allocation.cpp
+++ b/compiler-rt/test/asan/TestCases/asan_update_allocation.cpp
@@ -1,19 +1,32 @@
-// RUN: %clangxx_asan -O0 -DSIZE=10 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
-// RUN: %clangxx_asan -O0 -DSIZE=10000000 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK
+// RUN: %clangxx_asan -O0 %s -o %t
+
+// RUN: not %run %t 10 0 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefixes=CHECK,T0
+// RUN: not %run %t 10000000 0 2>&1 | FileCheck %s --check-prefixes=CHECK,T0
+
+// RUN: not %run %t 10 1 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefixes=CHECK,T1
+// RUN: not %run %t 10000000 1 2>&1 | FileCheck %s --check-prefixes=CHECK,T1
+
 // REQUIRES: stable-runtime
 
-#include <stdlib.h>
 #include <sanitizer/asan_interface.h>
+#include <stdlib.h>
+#include <thread>
 
 void UPDATE(void *p) {
   __asan_update_allocation_context(p);
 }
 
-int main() {
-  char *x = (char*)malloc(SIZE * sizeof(char));
-  UPDATE(x);
+int main(int argc, char *argv[]) {
+  char *x = (char *)malloc(atoi(argv[1]) * sizeof(char));
+  if (atoi(argv[2]))
+    std::thread([&]() { UPDATE(x); }).join();
+  else
+    UPDATE(x);
   free(x);
   return x[5];
   // CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}}
+  // CHECK: READ of size 1 at {{.*}} thread T0
+  // T0: allocated by thread T0 here
+  // T1: allocated by thread T1 here
   // CHECK: UPDATE
 }


        


More information about the llvm-commits mailing list