Skip to content

Commit 41934f2

Browse files
committed
[NFC][hwasan] Collect heap allocations early (#66682)
1 parent 22602c4 commit 41934f2

File tree

1 file changed

+61
-39
lines changed

1 file changed

+61
-39
lines changed

compiler-rt/lib/hwasan/hwasan_report.cpp

Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ class BaseReport {
391391
return;
392392

393393
CopyHeapChunk();
394-
CopyStackAllocations();
394+
CopyAllocations();
395395
candidate = FindBufferOverflowCandidate();
396396
}
397397

@@ -411,7 +411,7 @@ class BaseReport {
411411
};
412412

413413
void CopyHeapChunk();
414-
void CopyStackAllocations();
414+
void CopyAllocations();
415415
OverflowCandidate FindBufferOverflowCandidate() const;
416416
void PrintAddressDescription() const;
417417
void PrintHeapOrGlobalCandidate() const;
@@ -434,6 +434,15 @@ class BaseReport {
434434
} heap;
435435

436436
OverflowCandidate candidate;
437+
438+
uptr heap_allocations_count = 0;
439+
struct {
440+
HeapAllocationRecord har = {};
441+
uptr ring_index = 0;
442+
uptr num_matching_addrs = 0;
443+
uptr num_matching_addrs_4b = 0;
444+
u32 free_thread_id = 0;
445+
} heap_allocations[256];
437446
};
438447

439448
void BaseReport::CopyHeapChunk() {
@@ -446,12 +455,28 @@ void BaseReport::CopyHeapChunk() {
446455
}
447456
}
448457

449-
void BaseReport::CopyStackAllocations() {
458+
void BaseReport::CopyAllocations() {
450459
hwasanThreadList().VisitAllLiveThreads([&](Thread *t) {
451460
if (stack_allocations_count < ARRAY_SIZE(stack_allocations) &&
452461
t->AddrIsInStack(untagged_addr)) {
453462
stack_allocations[stack_allocations_count++].CopyFrom(t);
454463
}
464+
465+
if (heap_allocations_count < ARRAY_SIZE(heap_allocations)) {
466+
// Scan all threads' ring buffers to find if it's a heap-use-after-free.
467+
HeapAllocationRecord har;
468+
uptr ring_index, num_matching_addrs, num_matching_addrs_4b;
469+
if (FindHeapAllocation(t->heap_allocations(), tagged_addr, &har,
470+
&ring_index, &num_matching_addrs,
471+
&num_matching_addrs_4b)) {
472+
auto &ha = heap_allocations[heap_allocations_count++];
473+
ha.har = har;
474+
ha.ring_index = ring_index;
475+
ha.num_matching_addrs = num_matching_addrs;
476+
ha.num_matching_addrs_4b = num_matching_addrs_4b;
477+
ha.free_thread_id = t->unique_id();
478+
}
479+
}
455480
});
456481
}
457482

@@ -616,42 +641,39 @@ void BaseReport::PrintAddressDescription() const {
616641
num_descriptions_printed++;
617642
}
618643

619-
hwasanThreadList().VisitAllLiveThreads([&](Thread *t) {
620-
// Scan all threads' ring buffers to find if it's a heap-use-after-free.
621-
HeapAllocationRecord har;
622-
uptr ring_index, num_matching_addrs, num_matching_addrs_4b;
623-
if (FindHeapAllocation(t->heap_allocations(), tagged_addr, &har,
624-
&ring_index, &num_matching_addrs,
625-
&num_matching_addrs_4b)) {
626-
Printf("%s", d.Error());
627-
Printf("\nCause: use-after-free\n");
628-
Printf("%s", d.Location());
629-
Printf("%p is located %zd bytes inside a %zd-byte region [%p,%p)\n",
630-
untagged_addr, untagged_addr - UntagAddr(har.tagged_addr),
631-
har.requested_size, UntagAddr(har.tagged_addr),
632-
UntagAddr(har.tagged_addr) + har.requested_size);
633-
Printf("%s", d.Allocation());
634-
Printf("freed by thread T%u here:\n", t->unique_id());
635-
Printf("%s", d.Default());
636-
GetStackTraceFromId(har.free_context_id).Print();
637-
638-
Printf("%s", d.Allocation());
639-
Printf("previously allocated by thread T%u here:\n", har.alloc_thread_id);
640-
Printf("%s", d.Default());
641-
GetStackTraceFromId(har.alloc_context_id).Print();
642-
643-
// Print a developer note: the index of this heap object
644-
// in the thread's deallocation ring buffer.
645-
Printf("hwasan_dev_note_heap_rb_distance: %zd %zd\n", ring_index + 1,
646-
flags()->heap_history_size);
647-
Printf("hwasan_dev_note_num_matching_addrs: %zd\n", num_matching_addrs);
648-
Printf("hwasan_dev_note_num_matching_addrs_4b: %zd\n",
649-
num_matching_addrs_4b);
650-
651-
t->Announce();
652-
num_descriptions_printed++;
653-
}
654-
});
644+
for (uptr i = 0; i < heap_allocations_count; ++i) {
645+
const auto &ha = heap_allocations[i];
646+
const HeapAllocationRecord har = ha.har;
647+
648+
Printf("%s", d.Error());
649+
Printf("\nCause: use-after-free\n");
650+
Printf("%s", d.Location());
651+
Printf("%p is located %zd bytes inside a %zd-byte region [%p,%p)\n",
652+
untagged_addr, untagged_addr - UntagAddr(har.tagged_addr),
653+
har.requested_size, UntagAddr(har.tagged_addr),
654+
UntagAddr(har.tagged_addr) + har.requested_size);
655+
Printf("%s", d.Allocation());
656+
Printf("freed by thread T%u here:\n", ha.free_thread_id);
657+
Printf("%s", d.Default());
658+
GetStackTraceFromId(har.free_context_id).Print();
659+
660+
Printf("%s", d.Allocation());
661+
Printf("previously allocated by thread T%u here:\n", har.alloc_thread_id);
662+
Printf("%s", d.Default());
663+
GetStackTraceFromId(har.alloc_context_id).Print();
664+
665+
// Print a developer note: the index of this heap object
666+
// in the thread's deallocation ring buffer.
667+
Printf("hwasan_dev_note_heap_rb_distance: %zd %zd\n", ha.ring_index + 1,
668+
flags()->heap_history_size);
669+
Printf("hwasan_dev_note_num_matching_addrs: %zd\n", ha.num_matching_addrs);
670+
Printf("hwasan_dev_note_num_matching_addrs_4b: %zd\n",
671+
ha.num_matching_addrs_4b);
672+
673+
announce_by_id(ha.free_thread_id);
674+
// TODO: announce_by_id(har.alloc_thread_id);
675+
num_descriptions_printed++;
676+
}
655677

656678
if (candidate.untagged_addr && num_descriptions_printed == 0) {
657679
PrintHeapOrGlobalCandidate();

0 commit comments

Comments
 (0)