Index: compiler-rt/lib/asan/asan_errors.cc =================================================================== --- compiler-rt/lib/asan/asan_errors.cc +++ compiler-rt/lib/asan/asan_errors.cc @@ -58,17 +58,6 @@ SignalContext::DumpAllRegisters(context); } -static void MaybeReportNonExecRegion(uptr pc) { -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD - MemoryMappingLayout proc_maps(/*cache_enabled*/ true); - MemoryMappedSegment segment; - while (proc_maps.Next(&segment)) { - if (pc >= segment.start && pc < segment.end && !segment.IsExecutable()) - Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n"); - } -#endif -} - void ErrorDeadlySignal::Print() { Decorator d; Printf("%s", d.Warning()); Index: compiler-rt/lib/lsan/lsan.cc =================================================================== --- compiler-rt/lib/lsan/lsan.cc +++ compiler-rt/lib/lsan/lsan.cc @@ -65,6 +65,11 @@ if (common_flags()->help) parser.PrintFlagDescriptions(); } +void LsanOnDeadlySignal(int signo, void *siginfo, void *context) { + BufferedStackTrace stack; + ReportDeadlySignalAndDie(signo, siginfo, context, GetCurrentThread(), &stack); +} + extern "C" void __lsan_init() { CHECK(!lsan_init_is_running); if (lsan_inited) @@ -80,6 +85,7 @@ InitTlsSize(); InitializeInterceptors(); InitializeThreadRegistry(); + InstallDeadlySignalHandlers(LsanOnDeadlySignal); u32 tid = ThreadCreate(0, 0, true); CHECK_EQ(tid, 0); ThreadStart(tid, GetTid()); Index: compiler-rt/lib/lsan/lsan_interceptors.cc =================================================================== --- compiler-rt/lib/lsan/lsan_interceptors.cc +++ compiler-rt/lib/lsan/lsan_interceptors.cc @@ -401,6 +401,26 @@ REAL(_exit)(status); } +INTERCEPTOR(void *, signal, int signum, void *handler) { + if (GetHandleSignalMode(signum) != kHandleSignalExclusive) + return REAL(signal)(signum, handler); + return nullptr; +} + +INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act, + struct sigaction *oldact) { + if (GetHandleSignalMode(signum) != kHandleSignalExclusive) + return REAL(sigaction)(signum, act, oldact); + return 0; +} + +namespace __sanitizer { +int real_sigaction(int signum, const void *act, void *oldact) { + return REAL(sigaction)(signum, (const struct sigaction *)act, + (struct sigaction *)oldact); +} +} // namespace __sanitizer + namespace __lsan { void InitializeInterceptors() { @@ -421,6 +441,8 @@ INTERCEPT_FUNCTION(pthread_create); INTERCEPT_FUNCTION(pthread_join); INTERCEPT_FUNCTION(_exit); + INTERCEPT_FUNCTION(signal); + INTERCEPT_FUNCTION(sigaction); if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { Report("LeakSanitizer: failed to create thread key.\n"); Index: compiler-rt/lib/sanitizer_common/sanitizer_common.h =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_common.h +++ compiler-rt/lib/sanitizer_common/sanitizer_common.h @@ -307,6 +307,9 @@ typedef void (*SignalHandlerType)(int, void *, void *); HandleSignalMode GetHandleSignalMode(int signum); bool IsStackOverflow(int code, const struct SignalContext &sig); +void MaybeReportNonExecRegion(uptr pc); +void ReportDeadlySignalAndDie(int signo, void *siginfo, void *context, u32 tid, + struct BufferedStackTrace *stack); void InstallDeadlySignalHandlers(SignalHandlerType handler); const char *DescribeSignalOrException(int signo); // Alternative signal stack (POSIX-only). Index: compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -91,6 +91,8 @@ void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} void DisableCoreDumperIfNecessary() {} void InstallDeadlySignalHandlers(SignalHandlerType handler) {} +void ReportDeadlySignalAndDie(int signo, void *siginfo, void *context, u32 tid, + struct BufferedStackTrace *stack) {} void SetAlternateSignalStack() {} void UnsetAlternateSignalStack() {} void InitTlsSize() {} Index: compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -23,6 +23,7 @@ #include "sanitizer_posix.h" #include "sanitizer_procmaps.h" +#include "sanitizer_report_decorator.h" #include "sanitizer_stacktrace.h" #include "sanitizer_symbolizer.h" @@ -215,6 +216,84 @@ MaybeInstallSigaction(SIGFPE, handler); MaybeInstallSigaction(SIGILL, handler); } +static void UnwindSignalStackTrace(const SignalContext &sig, + BufferedStackTrace *stack) { + uptr top = 0; + uptr bottom = 0; + bool request_fast_unwind = common_flags()->fast_unwind_on_fatal; + if (request_fast_unwind) GetThreadStackTopAndBottom(false, &top, &bottom); + stack->Unwind(kStackTraceMax, sig.pc, sig.bp, sig.context, top, bottom, + request_fast_unwind); +} + +static void ReportStackOverflow(const SignalContext &sig, u32 tid, + const BufferedStackTrace &stack) { + SanitizerCommonDecorator d; + Printf("%s", d.Warning()); + static const char kDescription[] = "stack-overflow"; + Report("ERROR: %s: %s on address %p (pc %p bp %p sp %p T%d)\n", + SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc, + (void *)sig.bp, (void *)sig.sp, tid); + Printf("%s", d.End()); + stack.Print(); + ReportErrorSummary(kDescription, &stack); +} + +void MaybeReportNonExecRegion(uptr pc) { +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD + MemoryMappingLayout proc_maps(/*cache_enabled*/ true); + MemoryMappedSegment segment; + while (proc_maps.Next(&segment)) { + if (pc >= segment.start && pc < segment.end && !segment.IsExecutable()) + Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n"); + } +#endif +} + +static void ReportNonStackOverflow(int signo, const SignalContext &sig, u32 tid, + const BufferedStackTrace &stack) { + SanitizerCommonDecorator d; + Printf("%s", d.Warning()); + const char *description = __sanitizer::DescribeSignalOrException(signo); + Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n", + SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc, + (void *)sig.bp, (void *)sig.sp, tid); + Printf("%s", d.End()); + if (sig.pc < GetPageSizeCached()) + Report("Hint: pc points to the zero page.\n"); + if (sig.is_memory_access) { + const char *access_type = + sig.write_flag == SignalContext::WRITE + ? "WRITE" + : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN"); + Report("The signal is caused by a %s memory access.\n", access_type); + if (sig.addr < GetPageSizeCached()) + Report("Hint: address points to the zero page.\n"); + } + MaybeReportNonExecRegion(sig.pc); + stack.Print(); + Printf("%s can not provide additional info.\n", SanitizerToolName); + ReportErrorSummary(description, &stack); +} + +void ReportDeadlySignalAndDie(int signo, void *siginfo, void *context, u32 tid, + BufferedStackTrace *stack) { + // Write the first message using fd=2, just in case. + // It may actually fail to write in case stderr is closed. + internal_write(2, SanitizerToolName, internal_strlen(SanitizerToolName)); + static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; + internal_write(2, kDeadlySignal, sizeof(kDeadlySignal) - 1); + + SignalContext sig = SignalContext::Create(siginfo, context); + UnwindSignalStackTrace(sig, stack); + if (IsStackOverflow(((siginfo_t *)siginfo)->si_code, sig)) + ReportStackOverflow(sig, tid, *stack); + else + ReportNonStackOverflow(signo, sig, tid, *stack); + Report("ABORTING\n"); + Die(); +} + #endif // SANITIZER_GO bool IsAccessibleMemoryRange(uptr beg, uptr size) { Index: compiler-rt/lib/sanitizer_common/sanitizer_win.cc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_win.cc +++ compiler-rt/lib/sanitizer_common/sanitizer_win.cc @@ -858,6 +858,11 @@ // FIXME: Decide what to do on Windows. } +void ReportDeadlySignalAndDie(int signo, void *siginfo, void *context, u32 tid, + struct BufferedStackTrace *stack) { + // FIXME: Decide what to do on Windows. +} + HandleSignalMode GetHandleSignalMode(int signum) { // FIXME: Decide what to do on Windows. return kHandleSignalNo; Index: compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc =================================================================== --- compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc +++ compiler-rt/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc @@ -18,7 +18,6 @@ // clang-format on // Remove when fixed: https://github.com/google/sanitizers/issues/637 -// UNSUPPORTED: lsan // UNSUPPORTED: msan // UNSUPPORTED: tsan // UNSUPPORTED: ubsan @@ -77,17 +76,17 @@ return DoSEGV(); } -// CHECK0-NOT: AddressSanitizer:DEADLYSIGNAL -// CHECK0-NOT: AddressSanitizer: SEGV on unknown address +// CHECK0-NOT: Sanitizer:DEADLYSIGNAL +// CHECK0-NOT: Sanitizer: SEGV on unknown address // CHECK0: User sigaction installed // CHECK0-NEXT: User sigaction called // CHECK1: User sigaction installed // CHECK1-NEXT: User sigaction called -// CHECK1-NEXT: AddressSanitizer:DEADLYSIGNAL -// CHECK1: AddressSanitizer: SEGV on unknown address +// CHECK1-NEXT: {{Leak|Address}}Sanitizer:DEADLYSIGNAL +// CHECK1: {{Leak|Address}}Sanitizer: SEGV on unknown address // CHECK2-NOT: User sigaction called // CHECK2: User sigaction installed -// CHECK2-NEXT: AddressSanitizer:DEADLYSIGNAL -// CHECK2: AddressSanitizer: SEGV on unknown address +// CHECK2-NEXT: {{Leak|Address}}Sanitizer:DEADLYSIGNAL +// CHECK2: {{Leak|Address}}Sanitizer: SEGV on unknown address Index: compiler-rt/test/sanitizer_common/TestCases/Linux/assert.cc =================================================================== --- compiler-rt/test/sanitizer_common/TestCases/Linux/assert.cc +++ compiler-rt/test/sanitizer_common/TestCases/Linux/assert.cc @@ -5,7 +5,6 @@ // RUN: %env_tool_opts=handle_abort=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK1 %s // FIXME: implement in other sanitizers, not just asan. // XFAIL: msan -// XFAIL: lsan // XFAIL: tsan // XFAIL: ubsan #include Index: compiler-rt/test/sanitizer_common/TestCases/Linux/ill.cc =================================================================== --- compiler-rt/test/sanitizer_common/TestCases/Linux/ill.cc +++ compiler-rt/test/sanitizer_common/TestCases/Linux/ill.cc @@ -5,7 +5,6 @@ // RUN: %env_tool_opts=handle_sigill=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK1 %s // FIXME: implement in other sanitizers, not just asan. // XFAIL: msan -// XFAIL: lsan // XFAIL: tsan // XFAIL: ubsan // Index: compiler-rt/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc =================================================================== --- compiler-rt/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc +++ compiler-rt/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc @@ -9,7 +9,6 @@ // REQUIRES: stable-runtime // FIXME: implement SEGV handler in other sanitizers, not just asan. // XFAIL: msan -// XFAIL: lsan // XFAIL: tsan // XFAIL: ubsan Index: compiler-rt/test/sanitizer_common/TestCases/Posix/fpe.cc =================================================================== --- compiler-rt/test/sanitizer_common/TestCases/Posix/fpe.cc +++ compiler-rt/test/sanitizer_common/TestCases/Posix/fpe.cc @@ -5,7 +5,6 @@ // RUN: %env_tool_opts=handle_sigfpe=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK1 %s // FIXME: implement in other sanitizers, not just asan. // XFAIL: msan -// XFAIL: lsan // XFAIL: tsan // XFAIL: ubsan // Index: compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc =================================================================== --- compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc +++ compiler-rt/test/sanitizer_common/TestCases/Posix/sanitizer_set_report_fd_test.cc @@ -7,7 +7,6 @@ // REQUIRES: stable-runtime // FIXME: implement SEGV handler in other sanitizers, not just asan. // XFAIL: msan -// XFAIL: lsan // XFAIL: tsan // XFAIL: ubsan