Index: compiler-rt/trunk/lib/hwasan/hwasan.h =================================================================== --- compiler-rt/trunk/lib/hwasan/hwasan.h +++ compiler-rt/trunk/lib/hwasan/hwasan.h @@ -152,6 +152,8 @@ void UpdateMemoryUsage(); +void AppendToErrorMessageBuffer(const char *buffer); + } // namespace __hwasan #define HWASAN_MALLOC_HOOK(ptr, size) \ Index: compiler-rt/trunk/lib/hwasan/hwasan.cc =================================================================== --- compiler-rt/trunk/lib/hwasan/hwasan.cc +++ compiler-rt/trunk/lib/hwasan/hwasan.cc @@ -292,6 +292,7 @@ MadviseShadow(); + SetPrintfAndReportCallback(AppendToErrorMessageBuffer); // This may call libc -> needs initialized shadow. AndroidLogInit(); Index: compiler-rt/trunk/lib/hwasan/hwasan_linux.cc =================================================================== --- compiler-rt/trunk/lib/hwasan/hwasan_linux.cc +++ compiler-rt/trunk/lib/hwasan/hwasan_linux.cc @@ -358,11 +358,10 @@ GetStackTrace(stack, kStackTraceMax, StackTrace::GetNextInstructionPc(sig.pc), sig.bp, uc, common_flags()->fast_unwind_on_fatal); - ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store); - ++hwasan_report_count; - if (flags()->halt_on_error || !ai.recover) - Die(); + + bool fatal = flags()->halt_on_error || !ai.recover; + ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store, fatal); #if defined(__aarch64__) uc->uc_mcontext.pc += 4; Index: compiler-rt/trunk/lib/hwasan/hwasan_report.h =================================================================== --- compiler-rt/trunk/lib/hwasan/hwasan_report.h +++ compiler-rt/trunk/lib/hwasan/hwasan_report.h @@ -23,7 +23,7 @@ void ReportStats(); void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size, - bool is_store); + bool is_store, bool fatal); void ReportInvalidFree(StackTrace *stack, uptr addr); void ReportAtExitStatistics(); Index: compiler-rt/trunk/lib/hwasan/hwasan_report.cc =================================================================== --- compiler-rt/trunk/lib/hwasan/hwasan_report.cc +++ compiler-rt/trunk/lib/hwasan/hwasan_report.cc @@ -30,6 +30,49 @@ namespace __hwasan { +class ScopedReport { + public: + ScopedReport(bool fatal = false) : error_message_(1), fatal(fatal) { + BlockingMutexLock lock(&error_message_lock_); + error_message_ptr_ = fatal ? &error_message_ : nullptr; + } + + ~ScopedReport() { + BlockingMutexLock lock(&error_message_lock_); + if (fatal) { + SetAbortMessage(error_message_.data()); + Die(); + } + error_message_ptr_ = nullptr; + } + + static void MaybeAppendToErrorMessage(const char *msg) { + BlockingMutexLock lock(&error_message_lock_); + if (!error_message_ptr_) + return; + uptr len = internal_strlen(msg); + uptr old_size = error_message_ptr_->size(); + error_message_ptr_->resize(old_size + len); + // overwrite old trailing '\0', keep new trailing '\0' untouched. + internal_memcpy(&(*error_message_ptr_)[old_size - 1], msg, len); + } + private: + ScopedErrorReportLock error_report_lock_; + InternalMmapVector error_message_; + bool fatal; + + static InternalMmapVector *error_message_ptr_; + static BlockingMutex error_message_lock_; +}; + +InternalMmapVector *ScopedReport::error_message_ptr_; +BlockingMutex ScopedReport::error_message_lock_; + +// If there is an active ScopedReport, append to its error message. +void AppendToErrorMessageBuffer(const char *buffer) { + ScopedReport::MaybeAppendToErrorMessage(buffer); +} + static StackTrace GetStackTraceFromId(u32 id) { CHECK(id); StackTrace res = StackDepotGet(id); @@ -255,7 +298,8 @@ } void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) { - ScopedErrorReportLock l; + ScopedReport R(flags()->halt_on_error); + uptr untagged_addr = UntagAddr(tagged_addr); tag_t ptr_tag = GetTagFromPointer(tagged_addr); tag_t *tag_ptr = reinterpret_cast(MemToShadow(untagged_addr)); @@ -277,12 +321,11 @@ PrintTagsAroundAddr(tag_ptr); ReportErrorSummary(bug_type, stack); - Die(); } void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size, - bool is_store) { - ScopedErrorReportLock l; + bool is_store, bool fatal) { + ScopedReport R(fatal); SavedStackAllocations current_stack_allocations( GetCurrentThread()->stack_allocations()); Index: compiler-rt/trunk/test/hwasan/TestCases/abort-message-android.cc =================================================================== --- compiler-rt/trunk/test/hwasan/TestCases/abort-message-android.cc +++ compiler-rt/trunk/test/hwasan/TestCases/abort-message-android.cc @@ -0,0 +1,28 @@ +// RUN: %clangxx_hwasan -DERR=1 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_hwasan -DERR=2 %s -o %t && not %run %t 2>&1 | FileCheck %s +// REQUIRES: android + +#include +#include + +#include + +__attribute__((no_sanitize("hwaddress"))) +extern "C" void android_set_abort_message(const char *msg) { + fprintf(stderr, "== abort message start\n%s\n== abort message end\n", msg); +} + +int main() { + __hwasan_enable_allocator_tagging(); + char *volatile p = (char *)malloc(16); + if (ERR==1) { + p[16] = 1; + } else { + free(p); + free(p); + } + // CHECK: ERROR: HWAddressSanitizer: + // CHECK: == abort message start + // CHECK: ERROR: HWAddressSanitizer: + // CHECK: == abort message end +}