diff --git a/compiler-rt/include/sanitizer/hwasan_interface.h b/compiler-rt/include/sanitizer/hwasan_interface.h --- a/compiler-rt/include/sanitizer/hwasan_interface.h +++ b/compiler-rt/include/sanitizer/hwasan_interface.h @@ -73,6 +73,9 @@ * accessed through the pointer in x, or -1 if the whole range is good. */ intptr_t __hwasan_test_shadow(const volatile void *x, size_t size); + /* Sets the callback function to be called during HWASan error reporting. */ + void __hwasan_set_error_report_callback(void (*callback)(const char *)); + int __sanitizer_posix_memalign(void **memptr, size_t alignment, size_t size); void * __sanitizer_memalign(size_t alignment, size_t size); void * __sanitizer_aligned_alloc(size_t alignment, size_t size); diff --git a/compiler-rt/lib/hwasan/hwasan_interface_internal.h b/compiler-rt/lib/hwasan/hwasan_interface_internal.h --- a/compiler-rt/lib/hwasan/hwasan_interface_internal.h +++ b/compiler-rt/lib/hwasan/hwasan_interface_internal.h @@ -222,6 +222,9 @@ void *__hwasan_memset(void *s, int c, uptr n); SANITIZER_INTERFACE_ATTRIBUTE void *__hwasan_memmove(void *dest, const void *src, uptr n); + +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_set_error_report_callback(void (*callback)(const char *)); } // extern "C" #endif // HWASAN_INTERFACE_INTERNAL_H 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 @@ -43,12 +43,16 @@ } ~ScopedReport() { + void (*report_cb)(const char *); { BlockingMutexLock lock(&error_message_lock_); - if (fatal) - SetAbortMessage(error_message_.data()); + report_cb = error_report_callback_; error_message_ptr_ = nullptr; } + if (report_cb) + report_cb(error_message_.data()); + if (fatal) + SetAbortMessage(error_message_.data()); if (common_flags()->print_module_map >= 2 || (fatal && common_flags()->print_module_map)) DumpProcessMap(); @@ -66,6 +70,12 @@ // overwrite old trailing '\0', keep new trailing '\0' untouched. internal_memcpy(&(*error_message_ptr_)[old_size - 1], msg, len); } + + static void SetErrorReportCallback(void (*callback)(const char *)) { + BlockingMutexLock lock(&error_message_lock_); + error_report_callback_ = callback; + } + private: ScopedErrorReportLock error_report_lock_; InternalMmapVector error_message_; @@ -73,10 +83,12 @@ static InternalMmapVector *error_message_ptr_; static BlockingMutex error_message_lock_; + static void (*error_report_callback_)(const char *); }; InternalMmapVector *ScopedReport::error_message_ptr_; BlockingMutex ScopedReport::error_message_lock_; +void (*ScopedReport::error_report_callback_)(const char *); // If there is an active ScopedReport, append to its error message. void AppendToErrorMessageBuffer(const char *buffer) { @@ -650,3 +662,7 @@ } } // namespace __hwasan + +void __hwasan_set_error_report_callback(void (*callback)(const char *)) { + __hwasan::ScopedReport::SetErrorReportCallback(callback); +} diff --git a/compiler-rt/test/hwasan/TestCases/set-error-report-callback.cpp b/compiler-rt/test/hwasan/TestCases/set-error-report-callback.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/set-error-report-callback.cpp @@ -0,0 +1,31 @@ +// RUN: %clangxx_hwasan %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include +#include + +#include + +#include "utils.h" + +__attribute__((no_sanitize("hwaddress"))) extern "C" void callback(const char *msg) { + untag_fprintf(stderr, "== error start\n%s\n== error end\n", msg); +} + +int main() { + __hwasan_enable_allocator_tagging(); + __hwasan_set_error_report_callback(&callback); + char *volatile p = (char *)malloc(16); + p[16] = 1; + free(p); + // CHECK: ERROR: HWAddressSanitizer: + // CHECK: WRITE of size 1 at + // CHECK: allocated here: + // CHECK: Memory tags around the buggy address + + // CHECK: == error start + // CHECK: ERROR: HWAddressSanitizer: + // CHECK: WRITE of size 1 at + // CHECK: allocated here: + // CHECK: Memory tags around the buggy address + // CHECK: == error end +}