[compiler-rt] DO_NOT_MERGE (PR #66682)
Vitaly Buka via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 19 19:24:34 PDT 2023
https://github.com/vitalybuka updated https://github.com/llvm/llvm-project/pull/66682
>From c557621176f5f38b5757a325cc72be0a11a91c78 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Mon, 18 Sep 2023 12:35:54 -0700
Subject: [PATCH 1/8] [NFC][hwasan] Make ShowHeapOrGlobalCandidate a method
(#66682)
---
compiler-rt/lib/hwasan/hwasan_report.cpp | 148 ++++++++++++-----------
1 file changed, 75 insertions(+), 73 deletions(-)
diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp
index 6272e7116846cb4..3740cc4fc51d6dc 100644
--- a/compiler-rt/lib/hwasan/hwasan_report.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_report.cpp
@@ -319,77 +319,6 @@ static uptr GetGlobalSizeFromDescriptor(uptr ptr) {
return 0;
}
-static void ShowHeapOrGlobalCandidate(uptr untagged_addr, tag_t *candidate,
- tag_t *left, tag_t *right) {
- Decorator d;
- uptr mem = ShadowToMem(reinterpret_cast<uptr>(candidate));
- HwasanChunkView chunk = FindHeapChunkByAddress(mem);
- if (chunk.IsAllocated()) {
- uptr offset;
- const char *whence;
- if (untagged_addr < chunk.End() && untagged_addr >= chunk.Beg()) {
- offset = untagged_addr - chunk.Beg();
- whence = "inside";
- } else if (candidate == left) {
- offset = untagged_addr - chunk.End();
- whence = "after";
- } else {
- offset = chunk.Beg() - untagged_addr;
- whence = "before";
- }
- Printf("%s", d.Error());
- Printf("\nCause: heap-buffer-overflow\n");
- Printf("%s", d.Default());
- Printf("%s", d.Location());
- Printf("%p is located %zd bytes %s a %zd-byte region [%p,%p)\n",
- untagged_addr, offset, whence, chunk.UsedSize(), chunk.Beg(),
- chunk.End());
- Printf("%s", d.Allocation());
- Printf("allocated by thread T%u here:\n", chunk.GetAllocThreadId());
- Printf("%s", d.Default());
- GetStackTraceFromId(chunk.GetAllocStackId()).Print();
- return;
- }
- // Check whether the address points into a loaded library. If so, this is
- // most likely a global variable.
- const char *module_name;
- uptr module_address;
- Symbolizer *sym = Symbolizer::GetOrInit();
- if (sym->GetModuleNameAndOffsetForPC(mem, &module_name, &module_address)) {
- Printf("%s", d.Error());
- Printf("\nCause: global-overflow\n");
- Printf("%s", d.Default());
- DataInfo info;
- Printf("%s", d.Location());
- if (sym->SymbolizeData(mem, &info) && info.start) {
- Printf(
- "%p is located %zd bytes %s a %zd-byte global variable "
- "%s [%p,%p) in %s\n",
- untagged_addr,
- candidate == left ? untagged_addr - (info.start + info.size)
- : info.start - untagged_addr,
- candidate == left ? "after" : "before", info.size, info.name,
- info.start, info.start + info.size, module_name);
- } else {
- uptr size = GetGlobalSizeFromDescriptor(mem);
- if (size == 0)
- // We couldn't find the size of the global from the descriptors.
- Printf(
- "%p is located %s a global variable in "
- "\n #0 0x%x (%s+0x%x)\n",
- untagged_addr, candidate == left ? "after" : "before", mem,
- module_name, module_address);
- else
- Printf(
- "%p is located %s a %zd-byte global variable in "
- "\n #0 0x%x (%s+0x%x)\n",
- untagged_addr, candidate == left ? "after" : "before", size, mem,
- module_name, module_address);
- }
- Printf("%s", d.Default());
- }
-}
-
void ReportStats() {}
static void PrintTagInfoAroundAddr(tag_t *tag_ptr, uptr num_rows,
@@ -479,6 +408,8 @@ class BaseReport {
protected:
void PrintAddressDescription() const;
+ void PrintHeapOrGlobalCandidate(tag_t *candidate, tag_t *left,
+ tag_t *right) const;
ScopedReport scoped_report;
StackTrace *stack = nullptr;
@@ -498,6 +429,77 @@ class BaseReport {
} heap;
};
+void BaseReport::PrintHeapOrGlobalCandidate(tag_t *candidate, tag_t *left,
+ tag_t *right) const {
+ Decorator d;
+ uptr mem = ShadowToMem(reinterpret_cast<uptr>(candidate));
+ HwasanChunkView chunk = FindHeapChunkByAddress(mem);
+ if (chunk.IsAllocated()) {
+ uptr offset;
+ const char *whence;
+ if (untagged_addr < chunk.End() && untagged_addr >= chunk.Beg()) {
+ offset = untagged_addr - chunk.Beg();
+ whence = "inside";
+ } else if (candidate == left) {
+ offset = untagged_addr - chunk.End();
+ whence = "after";
+ } else {
+ offset = chunk.Beg() - untagged_addr;
+ whence = "before";
+ }
+ Printf("%s", d.Error());
+ Printf("\nCause: heap-buffer-overflow\n");
+ Printf("%s", d.Default());
+ Printf("%s", d.Location());
+ Printf("%p is located %zd bytes %s a %zd-byte region [%p,%p)\n",
+ untagged_addr, offset, whence, chunk.UsedSize(), chunk.Beg(),
+ chunk.End());
+ Printf("%s", d.Allocation());
+ Printf("allocated by thread T%u here:\n", chunk.GetAllocThreadId());
+ Printf("%s", d.Default());
+ GetStackTraceFromId(chunk.GetAllocStackId()).Print();
+ return;
+ }
+ // Check whether the address points into a loaded library. If so, this is
+ // most likely a global variable.
+ const char *module_name;
+ uptr module_address;
+ Symbolizer *sym = Symbolizer::GetOrInit();
+ if (sym->GetModuleNameAndOffsetForPC(mem, &module_name, &module_address)) {
+ Printf("%s", d.Error());
+ Printf("\nCause: global-overflow\n");
+ Printf("%s", d.Default());
+ DataInfo info;
+ Printf("%s", d.Location());
+ if (sym->SymbolizeData(mem, &info) && info.start) {
+ Printf(
+ "%p is located %zd bytes %s a %zd-byte global variable "
+ "%s [%p,%p) in %s\n",
+ untagged_addr,
+ candidate == left ? untagged_addr - (info.start + info.size)
+ : info.start - untagged_addr,
+ candidate == left ? "after" : "before", info.size, info.name,
+ info.start, info.start + info.size, module_name);
+ } else {
+ uptr size = GetGlobalSizeFromDescriptor(mem);
+ if (size == 0)
+ // We couldn't find the size of the global from the descriptors.
+ Printf(
+ "%p is located %s a global variable in "
+ "\n #0 0x%x (%s+0x%x)\n",
+ untagged_addr, candidate == left ? "after" : "before", mem,
+ module_name, module_address);
+ else
+ Printf(
+ "%p is located %s a %zd-byte global variable in "
+ "\n #0 0x%x (%s+0x%x)\n",
+ untagged_addr, candidate == left ? "after" : "before", size, mem,
+ module_name, module_address);
+ }
+ Printf("%s", d.Default());
+ }
+}
+
void BaseReport::PrintAddressDescription() const {
Decorator d;
int num_descriptions_printed = 0;
@@ -565,7 +567,7 @@ void BaseReport::PrintAddressDescription() const {
if (!stack_allocations_count && candidate &&
candidate_distance <= kCloseCandidateDistance) {
- ShowHeapOrGlobalCandidate(untagged_addr, candidate, left, right);
+ PrintHeapOrGlobalCandidate(candidate, left, right);
num_descriptions_printed++;
}
@@ -607,7 +609,7 @@ void BaseReport::PrintAddressDescription() const {
});
if (candidate && num_descriptions_printed == 0) {
- ShowHeapOrGlobalCandidate(untagged_addr, candidate, left, right);
+ PrintHeapOrGlobalCandidate(candidate, left, right);
num_descriptions_printed++;
}
>From 97abf2e75597abf7324ae31b8ca80dae5f89846f Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Mon, 18 Sep 2023 13:47:11 -0700
Subject: [PATCH 2/8] [NFC][hwasan] Find overflow candidate early (#66682)
---
compiler-rt/lib/hwasan/hwasan_report.cpp | 144 ++++++++++++++---------
1 file changed, 89 insertions(+), 55 deletions(-)
diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp
index 3740cc4fc51d6dc..d9a23ad29bc4bc8 100644
--- a/compiler-rt/lib/hwasan/hwasan_report.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_report.cpp
@@ -404,12 +404,28 @@ class BaseReport {
stack_allocations[stack_allocations_count++].CopyFrom(t);
}
});
+
+ candidate = FindBufferOverflowCandidate();
}
protected:
+ struct OverflowCandidate {
+ uptr untagged_addr = 0;
+ bool after = false;
+ bool is_close = false;
+
+ struct {
+ uptr begin = 0;
+ uptr end = 0;
+ u32 thread_id = 0;
+ u32 stack_id = 0;
+ bool is_allocated = false;
+ } heap;
+ };
+
+ OverflowCandidate FindBufferOverflowCandidate() const;
void PrintAddressDescription() const;
- void PrintHeapOrGlobalCandidate(tag_t *candidate, tag_t *left,
- tag_t *right) const;
+ void PrintHeapOrGlobalCandidate() const;
ScopedReport scoped_report;
StackTrace *stack = nullptr;
@@ -427,24 +443,64 @@ class BaseReport {
bool from_small_heap = false;
bool is_allocated = false;
} heap;
+
+ OverflowCandidate candidate;
};
-void BaseReport::PrintHeapOrGlobalCandidate(tag_t *candidate, tag_t *left,
- tag_t *right) const {
- Decorator d;
- uptr mem = ShadowToMem(reinterpret_cast<uptr>(candidate));
- HwasanChunkView chunk = FindHeapChunkByAddress(mem);
+BaseReport::OverflowCandidate BaseReport::FindBufferOverflowCandidate() const {
+ // Check if this looks like a heap buffer overflow by scanning
+ // the shadow left and right and looking for the first adjacent
+ // object with a different memory tag. If that tag matches ptr_tag,
+ // check the allocator if it has a live chunk there.
+ tag_t *tag_ptr = reinterpret_cast<tag_t *>(MemToShadow(untagged_addr));
+ tag_t *candidate_tag_ptr = nullptr, *left = tag_ptr, *right = tag_ptr;
+ uptr candidate_distance = 0;
+ for (; candidate_distance < 1000; candidate_distance++) {
+ if (MemIsShadow(reinterpret_cast<uptr>(left)) && TagsEqual(ptr_tag, left)) {
+ candidate_tag_ptr = left;
+ break;
+ }
+ --left;
+ if (MemIsShadow(reinterpret_cast<uptr>(right)) &&
+ TagsEqual(ptr_tag, right)) {
+ candidate_tag_ptr = right;
+ break;
+ }
+ ++right;
+ }
+
+ OverflowCandidate result = {};
+ constexpr auto kCloseCandidateDistance = 1;
+ result.is_close = candidate_distance <= kCloseCandidateDistance;
+
+ result.after = candidate_tag_ptr == left;
+ result.untagged_addr =
+ ShadowToMem(reinterpret_cast<uptr>(candidate_tag_ptr));
+ HwasanChunkView chunk = FindHeapChunkByAddress(result.untagged_addr);
if (chunk.IsAllocated()) {
+ result.heap.is_allocated = true;
+ result.heap.begin = chunk.Beg();
+ result.heap.end = chunk.End();
+ result.heap.thread_id = chunk.GetAllocThreadId();
+ result.heap.stack_id = chunk.GetAllocStackId();
+ }
+ return result;
+}
+
+void BaseReport::PrintHeapOrGlobalCandidate() const {
+ Decorator d;
+ if (candidate.heap.is_allocated) {
uptr offset;
const char *whence;
- if (untagged_addr < chunk.End() && untagged_addr >= chunk.Beg()) {
- offset = untagged_addr - chunk.Beg();
+ if (candidate.heap.begin <= untagged_addr &&
+ untagged_addr < candidate.heap.end) {
+ offset = untagged_addr - candidate.heap.begin;
whence = "inside";
- } else if (candidate == left) {
- offset = untagged_addr - chunk.End();
+ } else if (candidate.after) {
+ offset = untagged_addr - candidate.heap.end;
whence = "after";
} else {
- offset = chunk.Beg() - untagged_addr;
+ offset = candidate.heap.begin - untagged_addr;
whence = "before";
}
Printf("%s", d.Error());
@@ -452,12 +508,13 @@ void BaseReport::PrintHeapOrGlobalCandidate(tag_t *candidate, tag_t *left,
Printf("%s", d.Default());
Printf("%s", d.Location());
Printf("%p is located %zd bytes %s a %zd-byte region [%p,%p)\n",
- untagged_addr, offset, whence, chunk.UsedSize(), chunk.Beg(),
- chunk.End());
+ untagged_addr, offset, whence,
+ candidate.heap.end - candidate.heap.begin, candidate.heap.begin,
+ candidate.heap.end);
Printf("%s", d.Allocation());
- Printf("allocated by thread T%u here:\n", chunk.GetAllocThreadId());
+ Printf("allocated by thread T%u here:\n", candidate.heap.thread_id);
Printf("%s", d.Default());
- GetStackTraceFromId(chunk.GetAllocStackId()).Print();
+ GetStackTraceFromId(candidate.heap.stack_id).Print();
return;
}
// Check whether the address points into a loaded library. If so, this is
@@ -465,36 +522,37 @@ void BaseReport::PrintHeapOrGlobalCandidate(tag_t *candidate, tag_t *left,
const char *module_name;
uptr module_address;
Symbolizer *sym = Symbolizer::GetOrInit();
- if (sym->GetModuleNameAndOffsetForPC(mem, &module_name, &module_address)) {
+ if (sym->GetModuleNameAndOffsetForPC(candidate.untagged_addr, &module_name,
+ &module_address)) {
Printf("%s", d.Error());
Printf("\nCause: global-overflow\n");
Printf("%s", d.Default());
DataInfo info;
Printf("%s", d.Location());
- if (sym->SymbolizeData(mem, &info) && info.start) {
+ if (sym->SymbolizeData(candidate.untagged_addr, &info) && info.start) {
Printf(
"%p is located %zd bytes %s a %zd-byte global variable "
"%s [%p,%p) in %s\n",
untagged_addr,
- candidate == left ? untagged_addr - (info.start + info.size)
- : info.start - untagged_addr,
- candidate == left ? "after" : "before", info.size, info.name,
+ candidate.after ? untagged_addr - (info.start + info.size)
+ : info.start - untagged_addr,
+ candidate.after ? "after" : "before", info.size, info.name,
info.start, info.start + info.size, module_name);
} else {
- uptr size = GetGlobalSizeFromDescriptor(mem);
+ uptr size = GetGlobalSizeFromDescriptor(candidate.untagged_addr);
if (size == 0)
// We couldn't find the size of the global from the descriptors.
Printf(
"%p is located %s a global variable in "
"\n #0 0x%x (%s+0x%x)\n",
- untagged_addr, candidate == left ? "after" : "before", mem,
- module_name, module_address);
+ untagged_addr, candidate.after ? "after" : "before",
+ candidate.untagged_addr, module_name, module_address);
else
Printf(
"%p is located %s a %zd-byte global variable in "
"\n #0 0x%x (%s+0x%x)\n",
- untagged_addr, candidate == left ? "after" : "before", size, mem,
- module_name, module_address);
+ untagged_addr, candidate.after ? "after" : "before", size,
+ candidate.untagged_addr, module_name, module_address);
}
Printf("%s", d.Default());
}
@@ -524,7 +582,7 @@ void BaseReport::PrintAddressDescription() const {
// Check stack first. If the address is on the stack of a live thread, we
// know it cannot be a heap / global overflow.
for (uptr i = 0; i < stack_allocations_count; ++i) {
- auto &allocations = stack_allocations[i];
+ const auto &allocations = stack_allocations[i];
// TODO(fmayer): figure out how to distinguish use-after-return and
// stack-buffer-overflow.
Printf("%s", d.Error());
@@ -542,32 +600,8 @@ void BaseReport::PrintAddressDescription() const {
num_descriptions_printed++;
}
- // Check if this looks like a heap buffer overflow by scanning
- // the shadow left and right and looking for the first adjacent
- // object with a different memory tag. If that tag matches ptr_tag,
- // check the allocator if it has a live chunk there.
- tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
- tag_t *candidate = nullptr, *left = tag_ptr, *right = tag_ptr;
- uptr candidate_distance = 0;
- for (; candidate_distance < 1000; candidate_distance++) {
- if (MemIsShadow(reinterpret_cast<uptr>(left)) && TagsEqual(ptr_tag, left)) {
- candidate = left;
- break;
- }
- --left;
- if (MemIsShadow(reinterpret_cast<uptr>(right)) &&
- TagsEqual(ptr_tag, right)) {
- candidate = right;
- break;
- }
- ++right;
- }
-
- constexpr auto kCloseCandidateDistance = 1;
-
- if (!stack_allocations_count && candidate &&
- candidate_distance <= kCloseCandidateDistance) {
- PrintHeapOrGlobalCandidate(candidate, left, right);
+ if (!stack_allocations_count && candidate.untagged_addr && candidate.is_close) {
+ PrintHeapOrGlobalCandidate();
num_descriptions_printed++;
}
@@ -608,8 +642,8 @@ void BaseReport::PrintAddressDescription() const {
}
});
- if (candidate && num_descriptions_printed == 0) {
- PrintHeapOrGlobalCandidate(candidate, left, right);
+ if (candidate.untagged_addr && num_descriptions_printed == 0) {
+ PrintHeapOrGlobalCandidate();
num_descriptions_printed++;
}
>From 15c115d370136acf2f8b4f955115a196f4910b4b Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Mon, 18 Sep 2023 15:26:36 -0700
Subject: [PATCH 3/8] [NFC][hwasan] Extract a few BaseReport::Copy methods
(#66682)
---
compiler-rt/lib/hwasan/hwasan_report.cpp | 38 ++++++++++++++----------
1 file changed, 23 insertions(+), 15 deletions(-)
diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp
index d9a23ad29bc4bc8..cb8f874e247c4b1 100644
--- a/compiler-rt/lib/hwasan/hwasan_report.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_report.cpp
@@ -390,21 +390,8 @@ class BaseReport {
if (MemIsShadow(untagged_addr))
return;
- HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr);
- heap.begin = chunk.Beg();
- if (heap.begin) {
- heap.size = chunk.ActualSize();
- heap.from_small_heap = chunk.FromSmallHeap();
- heap.is_allocated = chunk.IsAllocated();
- }
-
- hwasanThreadList().VisitAllLiveThreads([&](Thread *t) {
- if (stack_allocations_count < ARRAY_SIZE(stack_allocations) &&
- t->AddrIsInStack(untagged_addr)) {
- stack_allocations[stack_allocations_count++].CopyFrom(t);
- }
- });
-
+ CopyHeapChunk();
+ CopyStackAllocations();
candidate = FindBufferOverflowCandidate();
}
@@ -423,6 +410,8 @@ class BaseReport {
} heap;
};
+ void CopyHeapChunk();
+ void CopyStackAllocations();
OverflowCandidate FindBufferOverflowCandidate() const;
void PrintAddressDescription() const;
void PrintHeapOrGlobalCandidate() const;
@@ -447,6 +436,25 @@ class BaseReport {
OverflowCandidate candidate;
};
+void BaseReport::CopyHeapChunk() {
+ HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr);
+ heap.begin = chunk.Beg();
+ if (heap.begin) {
+ heap.size = chunk.ActualSize();
+ heap.from_small_heap = chunk.FromSmallHeap();
+ heap.is_allocated = chunk.IsAllocated();
+ }
+}
+
+void BaseReport::CopyStackAllocations() {
+ hwasanThreadList().VisitAllLiveThreads([&](Thread *t) {
+ if (stack_allocations_count < ARRAY_SIZE(stack_allocations) &&
+ t->AddrIsInStack(untagged_addr)) {
+ stack_allocations[stack_allocations_count++].CopyFrom(t);
+ }
+ });
+}
+
BaseReport::OverflowCandidate BaseReport::FindBufferOverflowCandidate() const {
// Check if this looks like a heap buffer overflow by scanning
// the shadow left and right and looking for the first adjacent
>From a6cb11d7daead236661227ad67ffab8ceea510f0 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Mon, 18 Sep 2023 16:37:20 -0700
Subject: [PATCH 4/8] [NFC][hwasan] Extract announce_by_id (#66682)
---
compiler-rt/lib/hwasan/hwasan_report.cpp | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp
index cb8f874e247c4b1..46f4f8ae070a921 100644
--- a/compiler-rt/lib/hwasan/hwasan_report.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_report.cpp
@@ -587,6 +587,13 @@ void BaseReport::PrintAddressDescription() const {
untagged_addr - heap.begin, d.Default());
}
+ auto announce_by_id = [](u32 thread_id) {
+ hwasanThreadList().VisitAllLiveThreads([&](Thread *t) {
+ if (thread_id == t->unique_id())
+ t->Announce();
+ });
+ };
+
// Check stack first. If the address is on the stack of a live thread, we
// know it cannot be a heap / global overflow.
for (uptr i = 0; i < stack_allocations_count; ++i) {
@@ -599,11 +606,7 @@ void BaseReport::PrintAddressDescription() const {
Printf("Address %p is located in stack of thread T%zd\n", untagged_addr,
allocations.thread_id());
Printf("%s", d.Default());
- hwasanThreadList().VisitAllLiveThreads([&](Thread *t) {
- if (allocations.thread_id() == t->unique_id())
- t->Announce();
- });
-
+ announce_by_id(allocations.thread_id());
PrintStackAllocations(allocations.get(), ptr_tag, untagged_addr);
num_descriptions_printed++;
}
>From 9e7f527822d024a16b7707b0638b24954b35aaff Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Mon, 18 Sep 2023 16:38:15 -0700
Subject: [PATCH 5/8] [NFC][hwasan] Collect heap allocations early (#66682)
---
compiler-rt/lib/hwasan/hwasan_report.cpp | 100 ++++++++++++++---------
1 file changed, 61 insertions(+), 39 deletions(-)
diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp
index 46f4f8ae070a921..543d719311f7e59 100644
--- a/compiler-rt/lib/hwasan/hwasan_report.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_report.cpp
@@ -391,7 +391,7 @@ class BaseReport {
return;
CopyHeapChunk();
- CopyStackAllocations();
+ CopyAllocations();
candidate = FindBufferOverflowCandidate();
}
@@ -411,7 +411,7 @@ class BaseReport {
};
void CopyHeapChunk();
- void CopyStackAllocations();
+ void CopyAllocations();
OverflowCandidate FindBufferOverflowCandidate() const;
void PrintAddressDescription() const;
void PrintHeapOrGlobalCandidate() const;
@@ -434,6 +434,15 @@ class BaseReport {
} heap;
OverflowCandidate candidate;
+
+ uptr heap_allocations_count = 0;
+ struct {
+ HeapAllocationRecord har = {};
+ uptr ring_index = 0;
+ uptr num_matching_addrs = 0;
+ uptr num_matching_addrs_4b = 0;
+ u32 free_thread_id = 0;
+ } heap_allocations[256];
};
void BaseReport::CopyHeapChunk() {
@@ -446,12 +455,28 @@ void BaseReport::CopyHeapChunk() {
}
}
-void BaseReport::CopyStackAllocations() {
+void BaseReport::CopyAllocations() {
hwasanThreadList().VisitAllLiveThreads([&](Thread *t) {
if (stack_allocations_count < ARRAY_SIZE(stack_allocations) &&
t->AddrIsInStack(untagged_addr)) {
stack_allocations[stack_allocations_count++].CopyFrom(t);
}
+
+ if (heap_allocations_count < ARRAY_SIZE(heap_allocations)) {
+ // Scan all threads' ring buffers to find if it's a heap-use-after-free.
+ HeapAllocationRecord har;
+ uptr ring_index, num_matching_addrs, num_matching_addrs_4b;
+ if (FindHeapAllocation(t->heap_allocations(), tagged_addr, &har,
+ &ring_index, &num_matching_addrs,
+ &num_matching_addrs_4b)) {
+ auto &ha = heap_allocations[heap_allocations_count++];
+ ha.har = har;
+ ha.ring_index = ring_index;
+ ha.num_matching_addrs = num_matching_addrs;
+ ha.num_matching_addrs_4b = num_matching_addrs_4b;
+ ha.free_thread_id = t->unique_id();
+ }
+ }
});
}
@@ -616,42 +641,39 @@ void BaseReport::PrintAddressDescription() const {
num_descriptions_printed++;
}
- hwasanThreadList().VisitAllLiveThreads([&](Thread *t) {
- // Scan all threads' ring buffers to find if it's a heap-use-after-free.
- HeapAllocationRecord har;
- uptr ring_index, num_matching_addrs, num_matching_addrs_4b;
- if (FindHeapAllocation(t->heap_allocations(), tagged_addr, &har,
- &ring_index, &num_matching_addrs,
- &num_matching_addrs_4b)) {
- Printf("%s", d.Error());
- Printf("\nCause: use-after-free\n");
- Printf("%s", d.Location());
- Printf("%p is located %zd bytes inside a %zd-byte region [%p,%p)\n",
- untagged_addr, untagged_addr - UntagAddr(har.tagged_addr),
- har.requested_size, UntagAddr(har.tagged_addr),
- UntagAddr(har.tagged_addr) + har.requested_size);
- Printf("%s", d.Allocation());
- 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 by thread T%u here:\n", har.alloc_thread_id);
- Printf("%s", d.Default());
- GetStackTraceFromId(har.alloc_context_id).Print();
-
- // Print a developer note: the index of this heap object
- // in the thread's deallocation ring buffer.
- Printf("hwasan_dev_note_heap_rb_distance: %zd %zd\n", ring_index + 1,
- flags()->heap_history_size);
- Printf("hwasan_dev_note_num_matching_addrs: %zd\n", num_matching_addrs);
- Printf("hwasan_dev_note_num_matching_addrs_4b: %zd\n",
- num_matching_addrs_4b);
-
- t->Announce();
- num_descriptions_printed++;
- }
- });
+ for (uptr i = 0; i < heap_allocations_count; ++i) {
+ const auto &ha = heap_allocations[i];
+ const HeapAllocationRecord har = ha.har;
+
+ Printf("%s", d.Error());
+ Printf("\nCause: use-after-free\n");
+ Printf("%s", d.Location());
+ Printf("%p is located %zd bytes inside a %zd-byte region [%p,%p)\n",
+ untagged_addr, untagged_addr - UntagAddr(har.tagged_addr),
+ har.requested_size, UntagAddr(har.tagged_addr),
+ UntagAddr(har.tagged_addr) + har.requested_size);
+ Printf("%s", d.Allocation());
+ Printf("freed by thread T%u here:\n", ha.free_thread_id);
+ Printf("%s", d.Default());
+ GetStackTraceFromId(har.free_context_id).Print();
+
+ Printf("%s", d.Allocation());
+ Printf("previously allocated by thread T%u here:\n", har.alloc_thread_id);
+ Printf("%s", d.Default());
+ GetStackTraceFromId(har.alloc_context_id).Print();
+
+ // Print a developer note: the index of this heap object
+ // in the thread's deallocation ring buffer.
+ Printf("hwasan_dev_note_heap_rb_distance: %zd %zd\n", ha.ring_index + 1,
+ flags()->heap_history_size);
+ Printf("hwasan_dev_note_num_matching_addrs: %zd\n", ha.num_matching_addrs);
+ Printf("hwasan_dev_note_num_matching_addrs_4b: %zd\n",
+ ha.num_matching_addrs_4b);
+
+ announce_by_id(ha.free_thread_id);
+ // TODO: announce_by_id(har.alloc_thread_id);
+ num_descriptions_printed++;
+ }
if (candidate.untagged_addr && num_descriptions_printed == 0) {
PrintHeapOrGlobalCandidate();
>From c0cedecf71ce551e2c4b7eb36d953d09adca7035 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Mon, 18 Sep 2023 19:17:02 -0700
Subject: [PATCH 6/8] [NFC][hwasan] Use stored chunk in TailOverwrittenReport
(#66682)
---
compiler-rt/lib/hwasan/hwasan_report.cpp | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp
index 543d719311f7e59..9bcd131fae3adf9 100644
--- a/compiler-rt/lib/hwasan/hwasan_report.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_report.cpp
@@ -429,6 +429,7 @@ class BaseReport {
struct {
uptr begin = 0;
uptr size = 0;
+ u32 stack_id = 0;
bool from_small_heap = false;
bool is_allocated = false;
} heap;
@@ -452,6 +453,7 @@ void BaseReport::CopyHeapChunk() {
heap.size = chunk.ActualSize();
heap.from_small_heap = chunk.FromSmallHeap();
heap.is_allocated = chunk.IsAllocated();
+ heap.stack_id = chunk.GetAllocStackId();
}
}
@@ -779,12 +781,11 @@ TailOverwrittenReport::~TailOverwrittenReport() {
Printf("deallocated here:\n");
Printf("%s", d.Default());
stack->Print();
- HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr);
- if (chunk.Beg()) {
+ if (heap.begin) {
Printf("%s", d.Allocation());
Printf("allocated here:\n");
Printf("%s", d.Default());
- GetStackTraceFromId(chunk.GetAllocStackId()).Print();
+ GetStackTraceFromId(heap.stack_id).Print();
}
InternalScopedString s;
>From bab75f8414c29eeeabcec22aa47f1625f18aeeb7 Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Mon, 18 Sep 2023 19:29:57 -0700
Subject: [PATCH 7/8] [NFC][hwasan] Stored tail early (#66682)
---
compiler-rt/lib/hwasan/hwasan_report.cpp | 32 +++++++++++++-----------
1 file changed, 17 insertions(+), 15 deletions(-)
diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp
index 9bcd131fae3adf9..6ac3e38ef53d0e7 100644
--- a/compiler-rt/lib/hwasan/hwasan_report.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_report.cpp
@@ -750,24 +750,28 @@ class TailOverwrittenReport : public BaseReport {
uptr orig_size, const u8 *expected)
: BaseReport(stack, flags()->halt_on_error, tagged_addr, 0),
orig_size(orig_size),
- expected(expected) {}
+ tail_size(kShadowAlignment - (orig_size % kShadowAlignment)) {
+ CHECK_GT(tail_size, 0U);
+ CHECK_LT(tail_size, kShadowAlignment);
+ internal_memcpy(tail_copy,
+ reinterpret_cast<u8 *>(untagged_addr + orig_size),
+ tail_size);
+ internal_memcpy(actual_expected, expected, tail_size);
+ // Short granule is stashed in the last byte of the magic string. To avoid
+ // confusion, make the expected magic string contain the short granule tag.
+ if (orig_size % kShadowAlignment != 0)
+ actual_expected[tail_size - 1] = ptr_tag;
+ }
~TailOverwrittenReport();
private:
- uptr orig_size;
- const u8 *expected;
+ const uptr orig_size = 0;
+ const uptr tail_size = 0;
+ u8 actual_expected[kShadowAlignment] = {};
+ u8 tail_copy[kShadowAlignment] = {};
};
TailOverwrittenReport::~TailOverwrittenReport() {
- uptr tail_size = kShadowAlignment - (orig_size % kShadowAlignment);
- u8 actual_expected[kShadowAlignment];
- internal_memcpy(actual_expected, expected, tail_size);
- // Short granule is stashed in the last byte of the magic string. To avoid
- // confusion, make the expected magic string contain the short granule tag.
- if (orig_size % kShadowAlignment != 0) {
- actual_expected[tail_size - 1] = ptr_tag;
- }
-
Decorator d;
Printf("%s", d.Error());
const char *bug_type = "allocation-tail-overwritten";
@@ -789,9 +793,7 @@ TailOverwrittenReport::~TailOverwrittenReport() {
}
InternalScopedString s;
- CHECK_GT(tail_size, 0U);
- CHECK_LT(tail_size, kShadowAlignment);
- u8 *tail = reinterpret_cast<u8*>(untagged_addr + orig_size);
+ u8 *tail = tail_copy;
s.AppendF("Tail contains: ");
for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.AppendF(".. ");
for (uptr i = 0; i < tail_size; i++) s.AppendF("%02x ", tail[i]);
>From f3c0aabf1fee980b91e712a4970a178f70db7dfc Mon Sep 17 00:00:00 2001
From: Vitaly Buka <vitalybuka at google.com>
Date: Tue, 19 Sep 2023 18:54:06 -0700
Subject: [PATCH 8/8] [NFC][hwasan] Stored shadow bytes early (#66682)
---
compiler-rt/lib/hwasan/hwasan_report.cpp | 138 +++++++++++++++--------
1 file changed, 93 insertions(+), 45 deletions(-)
diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp
index 6ac3e38ef53d0e7..7aac23815543080 100644
--- a/compiler-rt/lib/hwasan/hwasan_report.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_report.cpp
@@ -25,6 +25,7 @@
#include "sanitizer_common/sanitizer_array_ref.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_mutex.h"
#include "sanitizer_common/sanitizer_report_decorator.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
@@ -321,55 +322,60 @@ static uptr GetGlobalSizeFromDescriptor(uptr ptr) {
void ReportStats() {}
-static void PrintTagInfoAroundAddr(tag_t *tag_ptr, uptr num_rows,
- void (*print_tag)(InternalScopedString &s,
- tag_t *tag)) {
+template <typename PrintTag>
+static void PrintTagInfoAroundAddr(uptr addr, uptr num_rows,
+ InternalScopedString &s,
+ PrintTag print_tag) {
const uptr row_len = 16; // better be power of two.
- tag_t *center_row_beg = reinterpret_cast<tag_t *>(
- RoundDownTo(reinterpret_cast<uptr>(tag_ptr), row_len));
- tag_t *beg_row = center_row_beg - row_len * (num_rows / 2);
- tag_t *end_row = center_row_beg + row_len * ((num_rows + 1) / 2);
- InternalScopedString s;
- for (tag_t *row = beg_row; row < end_row; row += row_len) {
+ uptr center_row_beg = RoundDownTo(addr, row_len);
+ uptr beg_row = center_row_beg - row_len * (num_rows / 2);
+ uptr end_row = center_row_beg + row_len * ((num_rows + 1) / 2);
+ for (uptr row = beg_row; row < end_row; row += row_len) {
s.Append(row == center_row_beg ? "=>" : " ");
- s.AppendF("%p:", (void *)ShadowToMem(reinterpret_cast<uptr>(row)));
+ s.AppendF("%p:", (void *)ShadowToMem(row));
for (uptr i = 0; i < row_len; i++) {
- s.Append(row + i == tag_ptr ? "[" : " ");
- print_tag(s, &row[i]);
- s.Append(row + i == tag_ptr ? "]" : " ");
+ s.Append(row + i == addr ? "[" : " ");
+ print_tag(s, row + i);
+ s.Append(row + i == addr ? "]" : " ");
}
s.AppendF("\n");
}
- Printf("%s", s.data());
}
-static void PrintTagsAroundAddr(tag_t *tag_ptr) {
- Printf(
+template <typename GetTag, typename GetShortTag>
+static void PrintTagsAroundAddr(uptr addr, GetTag get_tag,
+ GetShortTag get_short_tag) {
+ InternalScopedString s;
+ s.AppendF(
"Memory tags around the buggy address (one tag corresponds to %zd "
"bytes):\n",
kShadowAlignment);
- PrintTagInfoAroundAddr(tag_ptr, 17, [](InternalScopedString &s, tag_t *tag) {
- s.AppendF("%02x", *tag);
- });
+ PrintTagInfoAroundAddr(addr, 17, s,
+ [&](InternalScopedString &s, uptr tag_addr) {
+ tag_t tag = get_tag(tag_addr);
+ s.AppendF("%02x", tag);
+ });
Printf(
"Tags for short granules around the buggy address (one tag corresponds "
"to %zd bytes):\n",
kShadowAlignment);
- PrintTagInfoAroundAddr(tag_ptr, 3, [](InternalScopedString &s, tag_t *tag) {
- if (*tag >= 1 && *tag <= kShadowAlignment) {
- uptr granule_addr = ShadowToMem(reinterpret_cast<uptr>(tag));
- s.AppendF("%02x",
- *reinterpret_cast<u8 *>(granule_addr + kShadowAlignment - 1));
- } else {
- s.AppendF("..");
- }
- });
- Printf(
+ PrintTagInfoAroundAddr(addr, 3, s,
+ [&](InternalScopedString &s, uptr tag_addr) {
+ tag_t tag = get_tag(tag_addr);
+ if (tag >= 1 && tag <= kShadowAlignment) {
+ tag_t short_tag = get_short_tag(tag_addr);
+ s.AppendF("%02x", short_tag);
+ } else {
+ s.AppendF("..");
+ }
+ });
+ s.AppendF(
"See "
"https://clang.llvm.org/docs/"
"HardwareAssistedAddressSanitizerDesign.html#short-granules for a "
"description of short granule tags\n");
+ Printf("%s", s.data());
}
static uptr GetTopPc(StackTrace *stack) {
@@ -390,6 +396,7 @@ class BaseReport {
if (MemIsShadow(untagged_addr))
return;
+ CopyShadow();
CopyHeapChunk();
CopyAllocations();
candidate = FindBufferOverflowCandidate();
@@ -410,6 +417,9 @@ class BaseReport {
} heap;
};
+ void CopyShadow();
+ tag_t GetTagCopy(uptr addr) const;
+ tag_t GetShortTagCopy(uptr addr) const;
void CopyHeapChunk();
void CopyAllocations();
OverflowCandidate FindBufferOverflowCandidate() const;
@@ -423,6 +433,12 @@ class BaseReport {
uptr untagged_addr = 0;
tag_t ptr_tag = 0;
+ struct {
+ uptr addr = 0;
+ tag_t tags[256] = {};
+ tag_t short_tags[256] = {};
+ } shadow;
+
uptr stack_allocations_count = 0;
SavedStackAllocations stack_allocations[16];
@@ -446,6 +462,42 @@ class BaseReport {
} heap_allocations[256];
};
+void BaseReport::CopyShadow() {
+ if (!MemIsApp(untagged_addr))
+ return;
+
+ shadow.addr = MemToShadow(untagged_addr) - ARRAY_SIZE(shadow.tags) / 2;
+ for (uptr i = 0; i < ARRAY_SIZE(shadow.tags); ++i) {
+ uptr tag_addr = shadow.addr + i;
+ if (!MemIsShadow(tag_addr))
+ continue;
+ shadow.tags[i] = *reinterpret_cast<tag_t *>(tag_addr);
+ if (1 <= shadow.tags[i] && shadow.tags[i] <= kShadowAlignment) {
+ // TODO: use IsAccessibleMemoryRange
+ uptr granule_last_addr = ShadowToMem(tag_addr) + kShadowAlignment - 1;
+ shadow.short_tags[i] = *reinterpret_cast<tag_t *>(granule_last_addr);
+ }
+ }
+}
+
+tag_t BaseReport::GetTagCopy(uptr addr) const {
+ if (addr < shadow.addr)
+ return 0;
+ uptr idx = addr - shadow.addr;
+ if (idx >= ARRAY_SIZE(shadow.tags))
+ return 0;
+ return shadow.tags[idx];
+}
+
+tag_t BaseReport::GetShortTagCopy(uptr addr) const {
+ if (addr < shadow.addr)
+ return 0;
+ uptr idx = addr - shadow.addr;
+ if (idx >= ARRAY_SIZE(shadow.short_tags))
+ return 0;
+ return shadow.short_tags[idx];
+}
+
void BaseReport::CopyHeapChunk() {
HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr);
heap.begin = chunk.Beg();
@@ -707,15 +759,6 @@ class InvalidFreeReport : public BaseReport {
};
InvalidFreeReport::~InvalidFreeReport() {
- tag_t *tag_ptr = nullptr;
- tag_t mem_tag = 0;
- if (MemIsApp(untagged_addr)) {
- tag_ptr = reinterpret_cast<tag_t *>(MemToShadow(untagged_addr));
- if (MemIsShadow(reinterpret_cast<uptr>(tag_ptr)))
- mem_tag = *tag_ptr;
- else
- tag_ptr = nullptr;
- }
Decorator d;
Printf("%s", d.Error());
uptr pc = GetTopPc(stack);
@@ -729,16 +772,18 @@ InvalidFreeReport::~InvalidFreeReport() {
SanitizerToolName, bug_type, untagged_addr, pc);
}
Printf("%s", d.Access());
- if (tag_ptr)
- Printf("tags: %02x/%02x (ptr/mem)\n", ptr_tag, mem_tag);
+ if (shadow.addr)
+ Printf("tags: %02x/%02x (ptr/mem)\n", ptr_tag, GetTagCopy(untagged_addr));
Printf("%s", d.Default());
stack->Print();
PrintAddressDescription();
- if (tag_ptr)
- PrintTagsAroundAddr(tag_ptr);
+ if (shadow.addr)
+ PrintTagsAroundAddr(
+ untagged_addr, [&](uptr addr) { return GetTagCopy(addr); },
+ [&](uptr addr) { return GetShortTagCopy(addr); });
MaybePrintAndroidHelpUrl();
ReportErrorSummary(bug_type, stack);
@@ -820,8 +865,9 @@ TailOverwrittenReport::~TailOverwrittenReport() {
Printf("%s", s.data());
GetCurrentThread()->Announce();
- tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
- PrintTagsAroundAddr(tag_ptr);
+ PrintTagsAroundAddr(
+ untagged_addr, [&](uptr addr) { return GetTagCopy(addr); },
+ [&](uptr addr) { return GetShortTagCopy(addr); });
MaybePrintAndroidHelpUrl();
ReportErrorSummary(bug_type, stack);
@@ -898,7 +944,9 @@ TagMismatchReport::~TagMismatchReport() {
PrintAddressDescription();
t->Announce();
- PrintTagsAroundAddr(tag_ptr);
+ PrintTagsAroundAddr(
+ untagged_addr, [&](uptr addr) { return GetTagCopy(addr); },
+ [&](uptr addr) { return GetShortTagCopy(addr); });
if (registers_frame)
ReportRegisters(registers_frame, pc);
More information about the llvm-commits
mailing list