[compiler-rt] DO_NOT_MERGE (PR #66682)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 18 11:30:31 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-compiler-rt-sanitizer
<details>
<summary>Changes</summary>
- [NFC][hwasan] Create *Report classes
- [NFC][hwasan] Use unnamed namespace and static
- [NFC][hwasan] Move Report classes together
- [NFC][hwasan] Extract BaseReport
- [NFC][hwasan] Move PrintAddressDescription
- [NFC][hwasan] Store thread id in SavedStackAllocations
- [NFC][hwasan] Add access_size into base report
- [NFC][hwasan] Make PrintAddressDescription method of BaseReport
- [NFC][hwasan] Collect heap related data early
---
Full diff: https://github.com/llvm/llvm-project/pull/66682.diff
1 Files Affected:
- (modified) compiler-rt/lib/hwasan/hwasan_report.cpp (+223-124)
``````````diff
diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp
index d318e26c6a86849..924371a2e90cc05 100644
--- a/compiler-rt/lib/hwasan/hwasan_report.cpp
+++ b/compiler-rt/lib/hwasan/hwasan_report.cpp
@@ -37,7 +37,7 @@ namespace __hwasan {
class ScopedReport {
public:
- ScopedReport(bool fatal = false) : fatal(fatal) {
+ ScopedReport(bool fatal) : fatal(fatal) {
Lock lock(&error_message_lock_);
error_message_ptr_ = fatal ? &error_message_ : nullptr;
++hwasan_report_count;
@@ -108,29 +108,45 @@ static void MaybePrintAndroidHelpUrl() {
#endif
}
+namespace {
// A RAII object that holds a copy of the current thread stack ring buffer.
// The actual stack buffer may change while we are iterating over it (for
// example, Printf may call syslog() which can itself be built with hwasan).
class SavedStackAllocations {
public:
- SavedStackAllocations(StackAllocationsRingBuffer *rb) {
+ SavedStackAllocations() = default;
+
+ explicit SavedStackAllocations(Thread *t) { CopyFrom(t); }
+
+ void CopyFrom(Thread *t) {
+ StackAllocationsRingBuffer *rb = t->stack_allocations();
uptr size = rb->size() * sizeof(uptr);
void *storage =
MmapAlignedOrDieOnFatalError(size, size * 2, "saved stack allocations");
new (&rb_) StackAllocationsRingBuffer(*rb, storage);
+ thread_id_ = t->unique_id();
}
~SavedStackAllocations() {
- StackAllocationsRingBuffer *rb = get();
- UnmapOrDie(rb->StartOfStorage(), rb->size() * sizeof(uptr));
+ if (rb_) {
+ StackAllocationsRingBuffer *rb = get();
+ UnmapOrDie(rb->StartOfStorage(), rb->size() * sizeof(uptr));
+ }
+ }
+
+ const StackAllocationsRingBuffer *get() const {
+ return (const StackAllocationsRingBuffer *)&rb_;
}
StackAllocationsRingBuffer *get() {
return (StackAllocationsRingBuffer *)&rb_;
}
+ u32 thread_id() const { return thread_id_; }
+
private:
- uptr rb_;
+ uptr rb_ = 0;
+ u32 thread_id_;
};
class Decorator: public __sanitizer::SanitizerCommonDecorator {
@@ -143,6 +159,7 @@ class Decorator: public __sanitizer::SanitizerCommonDecorator {
const char *Location() { return Green(); }
const char *Thread() { return Green(); }
};
+} // namespace
static bool FindHeapAllocation(HeapAllocationsRingBuffer *rb, uptr tagged_addr,
HeapAllocationRecord *har, uptr *ring_index,
@@ -183,7 +200,7 @@ static bool FindHeapAllocation(HeapAllocationsRingBuffer *rb, uptr tagged_addr,
return false;
}
-static void PrintStackAllocations(StackAllocationsRingBuffer *sa,
+static void PrintStackAllocations(const StackAllocationsRingBuffer *sa,
tag_t addr_tag, uptr untagged_addr) {
uptr frames = Min((uptr)flags()->stack_history_size, sa->size());
bool found_local = false;
@@ -373,12 +390,117 @@ static void ShowHeapOrGlobalCandidate(uptr untagged_addr, tag_t *candidate,
}
}
-void PrintAddressDescription(
- uptr tagged_addr, uptr access_size,
- StackAllocationsRingBuffer *current_stack_allocations) {
+void ReportStats() {}
+
+static void PrintTagInfoAroundAddr(tag_t *tag_ptr, uptr num_rows,
+ void (*print_tag)(InternalScopedString &s,
+ tag_t *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) {
+ s.Append(row == center_row_beg ? "=>" : " ");
+ s.AppendF("%p:", (void *)ShadowToMem(reinterpret_cast<uptr>(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.AppendF("\n");
+ }
+ Printf("%s", s.data());
+}
+
+static void PrintTagsAroundAddr(tag_t *tag_ptr) {
+ Printf(
+ "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);
+ });
+
+ 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(
+ "See "
+ "https://clang.llvm.org/docs/"
+ "HardwareAssistedAddressSanitizerDesign.html#short-granules for a "
+ "description of short granule tags\n");
+}
+
+static uptr GetTopPc(StackTrace *stack) {
+ return stack->size ? StackTrace::GetPreviousInstructionPc(stack->trace[0])
+ : 0;
+}
+
+namespace {
+class BaseReport {
+ public:
+ BaseReport(StackTrace *stack, bool fatal, uptr tagged_addr, uptr access_size)
+ : scoped_report(fatal),
+ stack(stack),
+ tagged_addr(tagged_addr),
+ access_size(access_size),
+ untagged_addr(UntagAddr(tagged_addr)),
+ ptr_tag(GetTagFromPointer(tagged_addr)) {
+ 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_count < ARRAY_SIZE(stack_allocations) &&
+ t->AddrIsInStack(untagged_addr)) {
+ stack_allocations[stack_count++].CopyFrom(t);
+ }
+ });
+ }
+
+ protected:
+ void PrintAddressDescription() const;
+
+ ScopedReport scoped_report;
+ StackTrace *stack = nullptr;
+ uptr tagged_addr = 0;
+ uptr access_size = 0;
+ uptr untagged_addr = 0;
+ tag_t ptr_tag = 0;
+
+ uptr stack_count = 0;
+ SavedStackAllocations stack_allocations[16];
+
+ struct {
+ uptr begin = 0;
+ uptr size = 0;
+ bool from_small_heap = false;
+ bool is_allocated = false;
+ } heap;
+};
+
+void BaseReport::PrintAddressDescription() const {
Decorator d;
int num_descriptions_printed = 0;
- uptr untagged_addr = UntagAddr(tagged_addr);
if (MemIsShadow(untagged_addr)) {
Printf("%s%p is HWAsan shadow memory.\n%s", d.Location(), untagged_addr,
@@ -387,61 +509,54 @@ void PrintAddressDescription(
}
// Print some very basic information about the address, if it's a heap.
- HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr);
- if (uptr beg = chunk.Beg()) {
- uptr size = chunk.ActualSize();
- Printf("%s[%p,%p) is a %s %s heap chunk; "
- "size: %zd offset: %zd\n%s",
- d.Location(),
- beg, beg + size,
- chunk.FromSmallHeap() ? "small" : "large",
- chunk.IsAllocated() ? "allocated" : "unallocated",
- size, untagged_addr - beg,
- d.Default());
+ if (heap.begin) {
+ Printf(
+ "%s[%p,%p) is a %s %s heap chunk; "
+ "size: %zd offset: %zd\n%s",
+ d.Location(), heap.begin, heap.begin + heap.size,
+ heap.from_small_heap ? "small" : "large",
+ heap.is_allocated ? "allocated" : "unallocated", heap.size,
+ untagged_addr - heap.begin, d.Default());
}
- tag_t addr_tag = GetTagFromPointer(tagged_addr);
-
- bool on_stack = false;
// Check stack first. If the address is on the stack of a live thread, we
// know it cannot be a heap / global overflow.
- hwasanThreadList().VisitAllLiveThreads([&](Thread *t) {
- if (t->AddrIsInStack(untagged_addr)) {
- on_stack = true;
- // TODO(fmayer): figure out how to distinguish use-after-return and
- // stack-buffer-overflow.
- Printf("%s", d.Error());
- Printf("\nCause: stack tag-mismatch\n");
- Printf("%s", d.Location());
- Printf("Address %p is located in stack of thread T%zd\n", untagged_addr,
- t->unique_id());
- Printf("%s", d.Default());
- t->Announce();
-
- auto *sa = (t == GetCurrentThread() && current_stack_allocations)
- ? current_stack_allocations
- : t->stack_allocations();
- PrintStackAllocations(sa, addr_tag, untagged_addr);
- num_descriptions_printed++;
- }
- });
+ if (stack_count) {
+ hwasanThreadList().VisitAllLiveThreads([&](Thread *t) {
+ for (auto &allocations : stack_allocations) {
+ if (allocations.thread_id() == t->unique_id()) {
+ // TODO(fmayer): figure out how to distinguish use-after-return and
+ // stack-buffer-overflow.
+ Printf("%s", d.Error());
+ Printf("\nCause: stack tag-mismatch\n");
+ Printf("%s", d.Location());
+ Printf("Address %p is located in stack of thread T%zd\n",
+ untagged_addr, t->unique_id());
+ Printf("%s", d.Default());
+ t->Announce();
+
+ PrintStackAllocations(allocations.get(), ptr_tag, untagged_addr);
+ 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 addr_tag,
+ // 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(addr_tag, left)) {
+ if (MemIsShadow(reinterpret_cast<uptr>(left)) && TagsEqual(ptr_tag, left)) {
candidate = left;
break;
}
--left;
if (MemIsShadow(reinterpret_cast<uptr>(right)) &&
- TagsEqual(addr_tag, right)) {
+ TagsEqual(ptr_tag, right)) {
candidate = right;
break;
}
@@ -450,7 +565,8 @@ void PrintAddressDescription(
constexpr auto kCloseCandidateDistance = 1;
- if (!on_stack && candidate && candidate_distance <= kCloseCandidateDistance) {
+ if (!stack_count && candidate &&
+ candidate_distance <= kCloseCandidateDistance) {
ShowHeapOrGlobalCandidate(untagged_addr, candidate, left, right);
num_descriptions_printed++;
}
@@ -512,68 +628,16 @@ void PrintAddressDescription(
}
}
-void ReportStats() {}
-
-static void PrintTagInfoAroundAddr(tag_t *tag_ptr, uptr num_rows,
- void (*print_tag)(InternalScopedString &s,
- tag_t *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) {
- s.Append(row == center_row_beg ? "=>" : " ");
- s.AppendF("%p:", (void *)ShadowToMem(reinterpret_cast<uptr>(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.AppendF("\n");
- }
- Printf("%s", s.data());
-}
-
-static void PrintTagsAroundAddr(tag_t *tag_ptr) {
- Printf(
- "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);
- });
-
- 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(
- "See "
- "https://clang.llvm.org/docs/"
- "HardwareAssistedAddressSanitizerDesign.html#short-granules for a "
- "description of short granule tags\n");
-}
-
-uptr GetTopPc(StackTrace *stack) {
- return stack->size ? StackTrace::GetPreviousInstructionPc(stack->trace[0])
- : 0;
-}
+class InvalidFreeReport : public BaseReport {
+ public:
+ InvalidFreeReport(StackTrace *stack, uptr tagged_addr)
+ : BaseReport(stack, flags()->halt_on_error, tagged_addr, 0) {}
+ ~InvalidFreeReport();
-void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) {
- ScopedReport R(flags()->halt_on_error);
+ private:
+};
- uptr untagged_addr = UntagAddr(tagged_addr);
- tag_t ptr_tag = GetTagFromPointer(tagged_addr);
+InvalidFreeReport::~InvalidFreeReport() {
tag_t *tag_ptr = nullptr;
tag_t mem_tag = 0;
if (MemIsApp(untagged_addr)) {
@@ -602,7 +666,7 @@ void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) {
stack->Print();
- PrintAddressDescription(tagged_addr, 0, nullptr);
+ PrintAddressDescription();
if (tag_ptr)
PrintTagsAroundAddr(tag_ptr);
@@ -611,21 +675,31 @@ void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) {
ReportErrorSummary(bug_type, stack);
}
-void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size,
- const u8 *expected) {
+class TailOverwrittenReport : public BaseReport {
+ public:
+ explicit TailOverwrittenReport(StackTrace *stack, uptr tagged_addr,
+ uptr orig_size, const u8 *expected)
+ : BaseReport(stack, flags()->halt_on_error, tagged_addr, 0),
+ orig_size(orig_size),
+ expected(expected) {}
+ ~TailOverwrittenReport();
+
+ private:
+ uptr orig_size;
+ const u8 *expected;
+};
+
+TailOverwrittenReport::~TailOverwrittenReport() {
uptr tail_size = kShadowAlignment - (orig_size % kShadowAlignment);
u8 actual_expected[kShadowAlignment];
internal_memcpy(actual_expected, expected, tail_size);
- tag_t ptr_tag = GetTagFromPointer(tagged_addr);
// 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;
}
- ScopedReport R(flags()->halt_on_error);
Decorator d;
- uptr untagged_addr = UntagAddr(tagged_addr);
Printf("%s", d.Error());
const char *bug_type = "allocation-tail-overwritten";
Report("ERROR: %s: %s; heap object [%p,%p) of size %zd\n", SanitizerToolName,
@@ -683,14 +757,25 @@ void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size,
ReportErrorSummary(bug_type, stack);
}
-void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
- bool is_store, bool fatal, uptr *registers_frame) {
- ScopedReport R(fatal);
- SavedStackAllocations current_stack_allocations(
- GetCurrentThread()->stack_allocations());
+class TagMismatchReport : public BaseReport {
+ public:
+ explicit TagMismatchReport(StackTrace *stack, uptr tagged_addr,
+ uptr access_size, bool is_store, bool fatal,
+ uptr *registers_frame)
+ : BaseReport(stack, fatal, tagged_addr, access_size),
+ access_size(access_size),
+ is_store(is_store),
+ registers_frame(registers_frame) {}
+ ~TagMismatchReport();
+ private:
+ uptr access_size;
+ bool is_store;
+ uptr *registers_frame;
+};
+
+TagMismatchReport::~TagMismatchReport() {
Decorator d;
- uptr untagged_addr = UntagAddr(tagged_addr);
// TODO: when possible, try to print heap-use-after-free, etc.
const char *bug_type = "tag-mismatch";
uptr pc = GetTopPc(stack);
@@ -704,7 +789,6 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
__hwasan_test_shadow(reinterpret_cast<void *>(tagged_addr), access_size);
CHECK_GE(offset, 0);
CHECK_LT(offset, static_cast<sptr>(access_size));
- tag_t ptr_tag = GetTagFromPointer(tagged_addr);
tag_t *tag_ptr =
reinterpret_cast<tag_t *>(MemToShadow(untagged_addr + offset));
tag_t mem_tag = *tag_ptr;
@@ -741,8 +825,7 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
stack->Print();
- PrintAddressDescription(tagged_addr, access_size,
- current_stack_allocations.get());
+ PrintAddressDescription();
t->Announce();
PrintTagsAroundAddr(tag_ptr);
@@ -753,6 +836,22 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
MaybePrintAndroidHelpUrl();
ReportErrorSummary(bug_type, stack);
}
+} // namespace
+
+void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) {
+ InvalidFreeReport R(stack, tagged_addr);
+}
+
+void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size,
+ const u8 *expected) {
+ TailOverwrittenReport R(stack, tagged_addr, orig_size, expected);
+}
+
+void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
+ bool is_store, bool fatal, uptr *registers_frame) {
+ TagMismatchReport R(stack, tagged_addr, access_size, is_store, fatal,
+ registers_frame);
+}
// See the frame breakdown defined in __hwasan_tag_mismatch (from
// hwasan_tag_mismatch_{aarch64,riscv64}.S).
``````````
</details>
https://github.com/llvm/llvm-project/pull/66682
More information about the llvm-commits
mailing list