diff --git a/compiler-rt/lib/asan/asan_interface.h b/compiler-rt/lib/asan/asan_interface.h index c625a6217c0c..c1390ceb8af5 100644 --- a/compiler-rt/lib/asan/asan_interface.h +++ b/compiler-rt/lib/asan/asan_interface.h @@ -118,6 +118,13 @@ extern "C" { void __asan_set_error_report_callback(void (*callback)(const char*)) SANITIZER_INTERFACE_ATTRIBUTE; + // Sets the callback to be called right when ASan detects an error. + // This can be used to notice cases when ASan detects an error, but the + // program crashes before ASan report is printed. + // Passing 0 unsets the callback. + void __asan_set_on_error_callback(void (*callback)(void)) + SANITIZER_INTERFACE_ATTRIBUTE; + // Returns the estimated number of bytes that will be reserved by allocator // for request of "size" bytes. If ASan allocator can't allocate that much // memory, returns the maximal possible allocation size, otherwise returns diff --git a/compiler-rt/lib/asan/asan_report.cc b/compiler-rt/lib/asan/asan_report.cc index 883b84b26a23..1cabbcdd91ca 100644 --- a/compiler-rt/lib/asan/asan_report.cc +++ b/compiler-rt/lib/asan/asan_report.cc @@ -21,7 +21,7 @@ namespace __asan { -// ---------------------- Error report callback ------------------- {{{1 +// -------------------- User-specified callbacks ----------------- {{{1 static void (*error_report_callback)(const char*); static char *error_message_buffer = 0; static uptr error_message_buffer_pos = 0; @@ -40,6 +40,8 @@ void AppendToErrorMessageBuffer(const char *buffer) { } } +static void (*on_error_callback)(void); + // ---------------------- Helper functions ----------------------- {{{1 static void PrintBytes(const char *before, uptr *a) { @@ -219,6 +221,9 @@ class ScopedInErrorReport { SleepForSeconds(Max(5, flags()->sleep_before_dying + 1)); Die(); } + if (on_error_callback) { + on_error_callback(); + } AsanPrintf("====================================================" "=============\n"); AsanThread *curr_thread = asanThreadRegistry().GetCurrent(); @@ -409,3 +414,7 @@ void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) { error_message_buffer_pos = 0; } } + +void NOINLINE __asan_set_on_error_callback(void (*callback)(void)) { + on_error_callback = callback; +} diff --git a/compiler-rt/lib/asan/tests/asan_noinst_test.cc b/compiler-rt/lib/asan/tests/asan_noinst_test.cc index 44d4c3c845b2..e066d0be3a2a 100644 --- a/compiler-rt/lib/asan/tests/asan_noinst_test.cc +++ b/compiler-rt/lib/asan/tests/asan_noinst_test.cc @@ -530,6 +530,12 @@ TEST(AddressSanitizerInterface, DeathCallbackTest) { __asan_set_death_callback(NULL); } +TEST(AddressSanitizerInterface, OnErrorCallbackTest) { + __asan_set_on_error_callback(MyDeathCallback); + EXPECT_DEATH(DoDoubleFree(), "MyDeathCallback.*double-free"); + __asan_set_on_error_callback(NULL); +} + static const char* kUseAfterPoisonErrorMessage = "use-after-poison"; #define GOOD_ACCESS(ptr, offset) \