diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.h b/compiler-rt/lib/hwasan/hwasan_allocator.h --- a/compiler-rt/lib/hwasan/hwasan_allocator.h +++ b/compiler-rt/lib/hwasan/hwasan_allocator.h @@ -46,6 +46,7 @@ inline bool IsAllocated() const; inline u64 GetRequestedSize() const; inline u32 GetAllocStackId() const; + inline u32 GetAllocThreadId() const; inline void SetLsanTag(__lsan::ChunkTag tag); inline __lsan::ChunkTag GetLsanTag() const; }; @@ -100,6 +101,7 @@ uptr UsedSize() const; // Size requested by the user uptr ActualSize() const; // Size allocated by the allocator. u32 GetAllocStackId() const; + u32 GetAllocThreadId() const; bool FromSmallHeap() const; bool AddrIsInside(uptr addr) const; @@ -113,13 +115,12 @@ // Information about one (de)allocation that happened in the past. // These are recorded in a thread-local ring buffer. -// TODO: this is currently 24 bytes (20 bytes + alignment). -// Compress it to 16 bytes or extend it to be more useful. struct HeapAllocationRecord { uptr tagged_addr; - u32 alloc_context_id; - u32 free_context_id; - u32 requested_size; + u32 alloc_thread_id; + u32 alloc_context_id; + u32 free_context_id; + u32 requested_size; }; typedef RingBuffer HeapAllocationsRingBuffer; diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp --- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp +++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp @@ -64,6 +64,10 @@ return metadata_->GetAllocStackId(); } +u32 HwasanChunkView::GetAllocThreadId() const { + return metadata_->GetAllocThreadId(); +} + uptr HwasanChunkView::ActualSize() const { return allocator.GetActuallyAllocatedSize(reinterpret_cast(block_)); } @@ -106,6 +110,12 @@ return atomic_load(&alloc_context_id, memory_order_relaxed); } +inline u32 Metadata::GetAllocThreadId() const { + u64 context = atomic_load(&alloc_context_id, memory_order_relaxed); + u32 tid = context >> 32; + return tid; +} + void GetAllocatorStats(AllocatorStatCounters s) { allocator.GetStats(s); } @@ -296,6 +306,7 @@ uptr orig_size = meta->GetRequestedSize(); u32 free_context_id = StackDepotPut(*stack); u32 alloc_context_id = meta->GetAllocStackId(); + u32 alloc_thread_id = meta->GetAllocThreadId(); // Check tail magic. uptr tagged_size = TaggedSize(orig_size); @@ -347,8 +358,9 @@ if (t) { allocator.Deallocate(t->allocator_cache(), aligned_ptr); if (auto *ha = t->heap_allocations()) - ha->push({reinterpret_cast(tagged_ptr), alloc_context_id, - free_context_id, static_cast(orig_size)}); + ha->push({reinterpret_cast(tagged_ptr), alloc_thread_id, + alloc_context_id, free_context_id, + static_cast(orig_size)}); } else { SpinMutexLock l(&fallback_mutex); AllocatorCache *cache = &fallback_allocator_cache; diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp --- a/compiler-rt/lib/hwasan/hwasan_report.cpp +++ b/compiler-rt/lib/hwasan/hwasan_report.cpp @@ -331,7 +331,7 @@ untagged_addr, offset, whence, chunk.UsedSize(), chunk.Beg(), chunk.End()); Printf("%s", d.Allocation()); - Printf("allocated here:\n"); + Printf("allocated by thread T%u here:\n", chunk.GetAllocThreadId()); Printf("%s", d.Default()); GetStackTraceFromId(chunk.GetAllocStackId()).Print(); return; @@ -473,12 +473,12 @@ har.requested_size, UntagAddr(har.tagged_addr), UntagAddr(har.tagged_addr) + har.requested_size); Printf("%s", d.Allocation()); - Printf("freed by thread T%zd here:\n", t->unique_id()); + Printf("freed by thread T%u here:\n", t->unique_id()); Printf("%s", d.Default()); GetStackTraceFromId(har.free_context_id).Print(); Printf("%s", d.Allocation()); - Printf("previously allocated here:\n", t); + Printf("previously allocated by thread T%u here:\n", har.alloc_thread_id); Printf("%s", d.Default()); GetStackTraceFromId(har.alloc_context_id).Print(); diff --git a/compiler-rt/test/hwasan/TestCases/double-free.c b/compiler-rt/test/hwasan/TestCases/double-free.c --- a/compiler-rt/test/hwasan/TestCases/double-free.c +++ b/compiler-rt/test/hwasan/TestCases/double-free.c @@ -18,7 +18,7 @@ // of the fault. With TCO the free frame can be replaced with the interceptor. // CHECK: in {{.*}}free // CHECK: freed by thread {{.*}} here: - // CHECK: previously allocated here: + // CHECK: previously allocated by thread {{.*}} here: // CHECK: Memory tags around the buggy address (one tag corresponds to 16 bytes): // CHECK: =>{{.*}}[[MEM_TAG]] fprintf(stderr, "DONE\n"); diff --git a/compiler-rt/test/hwasan/TestCases/hwasan_symbolize.cpp b/compiler-rt/test/hwasan/TestCases/hwasan_symbolize.cpp --- a/compiler-rt/test/hwasan/TestCases/hwasan_symbolize.cpp +++ b/compiler-rt/test/hwasan/TestCases/hwasan_symbolize.cpp @@ -18,7 +18,7 @@ // LINKIFY: // CHECK: hwasan_symbolize.cpp:[[@LINE-2]] // CHECK: Cause: heap-buffer-overflow - // CHECK: allocated here: + // CHECK: allocated by thread {{.*}} here: // LINKIFY: // CHECK: hwasan_symbolize.cpp:[[@LINE-7]] return 0; diff --git a/compiler-rt/test/hwasan/TestCases/realloc-after-free.c b/compiler-rt/test/hwasan/TestCases/realloc-after-free.c --- a/compiler-rt/test/hwasan/TestCases/realloc-after-free.c +++ b/compiler-rt/test/hwasan/TestCases/realloc-after-free.c @@ -16,12 +16,12 @@ char * volatile x = (char*)malloc(40); free(x); x = realloc(x, realloc_size); -// CHECK: ERROR: HWAddressSanitizer: invalid-free on address -// CHECK: tags: [[PTR_TAG:..]]/[[MEM_TAG:..]] (ptr/mem) -// CHECK: freed by thread {{.*}} here: -// CHECK: previously allocated here: -// CHECK: Memory tags around the buggy address (one tag corresponds to 16 bytes): -// CHECK: =>{{.*}}[[MEM_TAG]] + // CHECK: ERROR: HWAddressSanitizer: invalid-free on address + // CHECK: tags: [[PTR_TAG:..]]/[[MEM_TAG:..]] (ptr/mem) + // CHECK: freed by thread {{.*}} here: + // CHECK: previously allocated by thread {{.*}} here: + // CHECK: Memory tags around the buggy address (one tag corresponds to 16 bytes): + // CHECK: =>{{.*}}[[MEM_TAG]] fprintf(stderr, "DONE\n"); __hwasan_disable_allocator_tagging(); // CHECK-NOT: DONE diff --git a/compiler-rt/test/hwasan/TestCases/set-error-report-callback.cpp b/compiler-rt/test/hwasan/TestCases/set-error-report-callback.cpp --- a/compiler-rt/test/hwasan/TestCases/set-error-report-callback.cpp +++ b/compiler-rt/test/hwasan/TestCases/set-error-report-callback.cpp @@ -17,13 +17,13 @@ free(p); // CHECK: ERROR: HWAddressSanitizer: // CHECK: WRITE of size 1 at - // CHECK: allocated here: + // CHECK: allocated by thread {{.*}} here: // CHECK: Memory tags around the buggy address // CHECK: == error start // CHECK: ERROR: HWAddressSanitizer: // CHECK: WRITE of size 1 at - // CHECK: allocated here: + // CHECK: allocated by thread {{.*}} here: // CHECK: Memory tags around the buggy address // CHECK: == error end } diff --git a/compiler-rt/test/hwasan/TestCases/tag_in_free.c b/compiler-rt/test/hwasan/TestCases/tag_in_free.c --- a/compiler-rt/test/hwasan/TestCases/tag_in_free.c +++ b/compiler-rt/test/hwasan/TestCases/tag_in_free.c @@ -33,7 +33,7 @@ #ifdef MALLOC // MALLOC: READ of size 1 at // MALLOC: is located 6 bytes after a 10-byte region - // MALLOC: allocated here: + // MALLOC: allocated by thread T0 here: char volatile x = p[16]; #endif free(p); @@ -41,7 +41,7 @@ // FREE: READ of size 1 at // FREE: is located 0 bytes inside a 10-byte region // FREE: freed by thread T0 here: - // FREE: previously allocated here: + // FREE: previously allocated by thread T0 here: char volatile y = p[0]; #endif diff --git a/compiler-rt/test/hwasan/TestCases/thread-uaf.c b/compiler-rt/test/hwasan/TestCases/thread-uaf.c --- a/compiler-rt/test/hwasan/TestCases/thread-uaf.c +++ b/compiler-rt/test/hwasan/TestCases/thread-uaf.c @@ -33,7 +33,7 @@ // CHECK: Cause: use-after-free // CHECK: freed by thread T2 here // CHECK: in Deallocate - // CHECK: previously allocated here: + // CHECK: previously allocated by thread T1 here: // CHECK: in Allocate // CHECK-DAG: Thread: T2 0x // CHECK-DAG: Thread: T3 0x diff --git a/compiler-rt/test/hwasan/TestCases/use-after-free.c b/compiler-rt/test/hwasan/TestCases/use-after-free.c --- a/compiler-rt/test/hwasan/TestCases/use-after-free.c +++ b/compiler-rt/test/hwasan/TestCases/use-after-free.c @@ -35,7 +35,7 @@ // CHECK: #0 {{.*}} in {{.*}}free{{.*}} {{.*}}hwasan_allocation_functions.cpp // CHECK: #1 {{.*}} in main {{.*}}use-after-free.c:[[@LINE-19]] - // CHECK: previously allocated here: + // CHECK: previously allocated by thread {{.*}} here: // CHECK: #0 {{.*}} in {{.*}}malloc{{.*}} {{.*}}hwasan_allocation_functions.cpp // CHECK: #1 {{.*}} in main {{.*}}use-after-free.c:[[@LINE-24]] // CHECK: Memory tags around the buggy address (one tag corresponds to 16 bytes):