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 @@ -204,13 +204,15 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { CHECK(tagged_ptr); HWASAN_FREE_HOOK(tagged_ptr); + void *untagged_ptr = InTaggableRegion(reinterpret_cast(tagged_ptr)) + ? UntagPtr(tagged_ptr) + : tagged_ptr; + if (!allocator.PointerIsMine(untagged_ptr)) + ReportWildFree(stack, reinterpret_cast(tagged_ptr)); if (!PointerAndMemoryTagsMatch(tagged_ptr)) ReportInvalidFree(stack, reinterpret_cast(tagged_ptr)); - void *untagged_ptr = InTaggableRegion(reinterpret_cast(tagged_ptr)) - ? UntagPtr(tagged_ptr) - : tagged_ptr; void *aligned_ptr = reinterpret_cast( RoundDownTo(reinterpret_cast(untagged_ptr), kShadowAlignment)); tag_t pointer_tag = GetTagFromPointer(reinterpret_cast(tagged_ptr)); @@ -278,6 +280,12 @@ static void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old, uptr new_size, uptr alignment) { + void *untagged_ptr_old = + InTaggableRegion(reinterpret_cast(tagged_ptr_old)) + ? UntagPtr(tagged_ptr_old) + : tagged_ptr_old; + if (!allocator.PointerIsMine(untagged_ptr_old)) + ReportWildFree(stack, reinterpret_cast(tagged_ptr_old)); if (!PointerAndMemoryTagsMatch(tagged_ptr_old)) ReportInvalidFree(stack, reinterpret_cast(tagged_ptr_old)); diff --git a/compiler-rt/lib/hwasan/hwasan_report.h b/compiler-rt/lib/hwasan/hwasan_report.h --- a/compiler-rt/lib/hwasan/hwasan_report.h +++ b/compiler-rt/lib/hwasan/hwasan_report.h @@ -28,7 +28,7 @@ const u8 *expected); void ReportRegisters(uptr *registers_frame, uptr pc); void ReportAtExitStatistics(); - +void ReportWildFree(StackTrace *stack, uptr addr); } // namespace __hwasan 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 @@ -728,6 +728,20 @@ frame[29], frame[30], reinterpret_cast(frame) + 256); } +void ReportWildFree(StackTrace *stack, uptr untagged_addr) { + ScopedReport report(/*fatal=*/true); + uptr pc = GetTopPc(stack); + const Thread *thread = GetCurrentThread(); + if (thread) { + Report("ERROR: %s: wild-free on address %p at pc %p on thread T%zd\n", + SanitizerToolName, untagged_addr, pc, thread->unique_id()); + } else { + Report("ERROR: %s: wild-free on address %p at pc %p on unknown thread\n", + SanitizerToolName, untagged_addr, pc); + } + stack->Print(); +} + } // namespace __hwasan void __hwasan_set_error_report_callback(void (*callback)(const char *)) { diff --git a/compiler-rt/test/hwasan/TestCases/wild-free-realloc.c b/compiler-rt/test/hwasan/TestCases/wild-free-realloc.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/wild-free-realloc.c @@ -0,0 +1,15 @@ +// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s +// REQUIRES: stable-runtime + +#include + +int main() { + char *p = (char *)malloc(1); + realloc(p + 0x10000000000, 2); + // CHECK: ERROR: HWAddressSanitizer: wild-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread T{{[0-9]+}} + // CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in realloc + // CHECK: #1 {{.*}} in main {{.*}}wild-free-realloc.c:[[@LINE-3]] + // CHECK-NOT: Segmentation fault + // CHECK-NOT: SIGSEGV + return 0; +} diff --git a/compiler-rt/test/hwasan/TestCases/wild-free.c b/compiler-rt/test/hwasan/TestCases/wild-free.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/wild-free.c @@ -0,0 +1,15 @@ +// RUN: %clang_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s +// REQUIRES: stable-runtime + +#include + +int main() { + char *p = (char *)malloc(1); + free(p + 0x10000000000); + // CHECK: ERROR: HWAddressSanitizer: wild-free on address {{.*}} at pc {{[0x]+}}[[PC:.*]] on thread T{{[0-9]+}} + // CHECK: #0 {{[0x]+}}{{.*}}[[PC]] in free + // CHECK: #1 {{.*}} in main {{.*}}wild-free.c:[[@LINE-3]] + // CHECK-NOT: Segmentation fault + // CHECK-NOT: SIGSEGV + return 0; +}