diff --git a/compiler-rt/include/sanitizer/common_interface_defs.h b/compiler-rt/include/sanitizer/common_interface_defs.h index 6d4326f74021..d11cb1addc27 100644 --- a/compiler-rt/include/sanitizer/common_interface_defs.h +++ b/compiler-rt/include/sanitizer/common_interface_defs.h @@ -65,6 +65,11 @@ extern "C" { void __sanitizer_unaligned_store32(void *p, uint32_t x); void __sanitizer_unaligned_store64(void *p, uint64_t x); + // Returns 1 on the first call, then returns 0 thereafter. Called by the tool + // to ensure only one report is printed when multiple errors occur + // simultaneously. + int __sanitizer_acquire_crash_state(); + // Annotate the current state of a contiguous container, such as // std::vector, std::string or similar. // A contiguous container is a container that keeps all of its elements diff --git a/compiler-rt/lib/asan/asan_report.cc b/compiler-rt/lib/asan/asan_report.cc index 7c827c6a1359..271e89a75a30 100644 --- a/compiler-rt/lib/asan/asan_report.cc +++ b/compiler-rt/lib/asan/asan_report.cc @@ -134,6 +134,10 @@ class ScopedInErrorReport { } ~ScopedInErrorReport() { + if (halt_on_error_ && !__sanitizer_acquire_crash_state()) { + asanThreadRegistry().Unlock(); + return; + } ASAN_ON_ERROR(); if (current_error_.IsValid()) current_error_.Print(); diff --git a/compiler-rt/lib/fuzzer/FuzzerExtFunctions.def b/compiler-rt/lib/fuzzer/FuzzerExtFunctions.def index 25a655bfd71d..70f4b27fd18e 100644 --- a/compiler-rt/lib/fuzzer/FuzzerExtFunctions.def +++ b/compiler-rt/lib/fuzzer/FuzzerExtFunctions.def @@ -29,6 +29,7 @@ EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t, EXT_FUNC(__lsan_enable, void, (), false); EXT_FUNC(__lsan_disable, void, (), false); EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false); +EXT_FUNC(__sanitizer_acquire_crash_state, bool, (), true); EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int, (void (*malloc_hook)(const volatile void *, size_t), void (*free_hook)(const volatile void *)), diff --git a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp index cd835bea56ea..7a26370b3d46 100644 --- a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp @@ -228,6 +228,9 @@ void Fuzzer::StaticFileSizeExceedCallback() { } void Fuzzer::CrashCallback() { + if (EF->__sanitizer_acquire_crash_state && + !EF->__sanitizer_acquire_crash_state()) + return; Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid()); if (EF->__sanitizer_print_stack_trace) EF->__sanitizer_print_stack_trace(); @@ -243,6 +246,9 @@ void Fuzzer::CrashCallback() { void Fuzzer::ExitCallback() { if (!RunningCB) return; // This exit did not come from the user callback + if (EF->__sanitizer_acquire_crash_state && + !EF->__sanitizer_acquire_crash_state()) + return; Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid()); if (EF->__sanitizer_print_stack_trace) EF->__sanitizer_print_stack_trace(); @@ -282,6 +288,9 @@ void Fuzzer::AlarmCallback() { if (Options.Verbosity >= 2) Printf("AlarmCallback %zd\n", Seconds); if (Seconds >= (size_t)Options.UnitTimeoutSec) { + if (EF->__sanitizer_acquire_crash_state && + !EF->__sanitizer_acquire_crash_state()) + return; Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds); Printf(" and the timeout value is %d (use -timeout=N to change)\n", Options.UnitTimeoutSec); @@ -297,6 +306,9 @@ void Fuzzer::AlarmCallback() { } void Fuzzer::RssLimitCallback() { + if (EF->__sanitizer_acquire_crash_state && + !EF->__sanitizer_acquire_crash_state()) + return; Printf( "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n", GetPid(), GetPeakRSSMb(), Options.RssLimitMb); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.cc b/compiler-rt/lib/sanitizer_common/sanitizer_common.cc index 04e3dd7f7884..707de3d55fb5 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.cc @@ -14,6 +14,7 @@ #include "sanitizer_common.h" #include "sanitizer_allocator_interface.h" #include "sanitizer_allocator_internal.h" +#include "sanitizer_atomic.h" #include "sanitizer_flags.h" #include "sanitizer_libc.h" #include "sanitizer_placement_new.h" @@ -343,6 +344,12 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary, Printf("%s\n", error_summary); } +SANITIZER_INTERFACE_ATTRIBUTE +int __sanitizer_acquire_crash_state() { + static atomic_uint8_t in_crash_state = {}; + return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed); +} + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_set_death_callback(void (*callback)(void)) { SetUserDieCallback(callback); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc index 2568df3a5bff..377580cb0b4e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interface.inc @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// // Sanitizer Common interface list. //===----------------------------------------------------------------------===// +INTERFACE_FUNCTION(__sanitizer_acquire_crash_state) INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container) INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address) INTERFACE_FUNCTION(__sanitizer_set_death_callback) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h b/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h index 942f0b1cb586..f53d9557eab4 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h @@ -52,6 +52,12 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage(); SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(__sanitizer::u32 *guard); + + // Returns 1 on the first call, then returns 0 thereafter. Called by the tool + // to ensure only one report is printed when multiple errors occur + // simultaneously. + SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_acquire_crash_state(); + SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_annotate_contiguous_container(const void *beg, const void *end, diff --git a/compiler-rt/test/fuzzer/AcquireCrashStateTest.cpp b/compiler-rt/test/fuzzer/AcquireCrashStateTest.cpp new file mode 100644 index 000000000000..0fe71fd46bf4 --- /dev/null +++ b/compiler-rt/test/fuzzer/AcquireCrashStateTest.cpp @@ -0,0 +1,18 @@ +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. + +// Ensures that error reports are suppressed after +// __sanitizer_acquire_crash_state() has been called the first time. +#include "sanitizer/common_interface_defs.h" + +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + assert(Data); + if (Size == 0) return 0; + __sanitizer_acquire_crash_state(); + exit(0); // No report should be generated here. +} + diff --git a/compiler-rt/test/fuzzer/acquire-crash-state.test b/compiler-rt/test/fuzzer/acquire-crash-state.test new file mode 100644 index 000000000000..db893df904b3 --- /dev/null +++ b/compiler-rt/test/fuzzer/acquire-crash-state.test @@ -0,0 +1,3 @@ +RUN: %cpp_compiler %S/AcquireCrashStateTest.cpp -o %t +RUN: %t 2>&1 | FileCheck %s +CHECK-NOT: fuzz target exited