diff options
| author | Kostya Kortchinsky <kostyak@google.com> | 2018-04-16 16:32:19 +0000 |
|---|---|---|
| committer | Kostya Kortchinsky <kostyak@google.com> | 2018-04-16 16:32:19 +0000 |
| commit | 596b8b4a2268c0e60c6eb9b7147b3e423dee8a93 (patch) | |
| tree | 0ec039208da84dd15a40119265f3956bcfada939 /compiler-rt/lib/sanitizer_common | |
| parent | 1b06cc78177bec39509ae43583312fe3bab4468b (diff) | |
| download | bcm5719-llvm-596b8b4a2268c0e60c6eb9b7147b3e423dee8a93.tar.gz bcm5719-llvm-596b8b4a2268c0e60c6eb9b7147b3e423dee8a93.zip | |
[sanitizer] Split Symbolizer/StackTraces from core RTSanitizerCommon
Summary:
Host symbolizer & stacktraces related code in their own RT:
`RTSanitizerCommonSymbolizer`, which is "libcdep" by nature. Symbolizer &
stacktraces specific code that used to live in common files is moved to a new
file `sanitizer_symbolizer_report.cc` as is.
The purpose of this is the enforce a separation between code that relies on
symbolization and code that doesn't. This saves the inclusion of spurious code
due to the interface functions with default visibility, and the extra data
associated.
The following sanitizers makefiles were modified & tested locally:
- dfsan: doesn't require the new symbolizer RT
- esan: requires it
- hwasan: requires it
- lsan: requires it
- msan: requires it
- safestack: doesn't require it
- xray: doesn't require it
- tsan: requires it
- ubsan: requires it
- ubsan_minimal: doesn't require it
- scudo: requires it (but not for Fuchsia that has a minimal runtime)
This was tested locally on Linux, Android, Fuchsia.
Reviewers: alekseyshl, eugenis, dberris, kubamracek, vitalybuka, dvyukov, mcgrathr
Reviewed By: alekseyshl, vitalybuka
Subscribers: srhines, kubamracek, mgorny, krytarowski, delcypher, llvm-commits, #sanitizers
Differential Revision: https://reviews.llvm.org/D45457
llvm-svn: 330131
Diffstat (limited to 'compiler-rt/lib/sanitizer_common')
12 files changed, 363 insertions, 333 deletions
diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt index 25255889f67..e37fe1b18c0 100644 --- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt +++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt @@ -31,16 +31,8 @@ set(SANITIZER_SOURCES_NOTERMINATION sanitizer_procmaps_mac.cc sanitizer_procmaps_solaris.cc sanitizer_solaris.cc - sanitizer_stackdepot.cc - sanitizer_stacktrace.cc - sanitizer_stacktrace_printer.cc sanitizer_stoptheworld_mac.cc sanitizer_suppressions.cc - sanitizer_symbolizer.cc - sanitizer_symbolizer_fuchsia.cc - sanitizer_symbolizer_libbacktrace.cc - sanitizer_symbolizer_mac.cc - sanitizer_symbolizer_win.cc sanitizer_tls_get_addr.cc sanitizer_thread_registry.cc sanitizer_win.cc) @@ -67,12 +59,7 @@ set(SANITIZER_LIBCDEP_SOURCES sanitizer_linux_libcdep.cc sanitizer_mac_libcdep.cc sanitizer_posix_libcdep.cc - sanitizer_stacktrace_libcdep.cc - sanitizer_stoptheworld_linux_libcdep.cc - sanitizer_symbolizer_libcdep.cc - sanitizer_symbolizer_posix_libcdep.cc - sanitizer_unwind_linux_libcdep.cc - sanitizer_unwind_win.cc) + sanitizer_stoptheworld_linux_libcdep.cc) set(SANITIZER_COVERAGE_SOURCES sancov_flags.cc @@ -80,6 +67,22 @@ set(SANITIZER_COVERAGE_SOURCES sanitizer_coverage_libcdep_new.cc sanitizer_coverage_win_sections.cc) +set(SANITIZER_SYMBOLIZER_SOURCES + sanitizer_stackdepot.cc + sanitizer_stacktrace.cc + sanitizer_stacktrace_libcdep.cc + sanitizer_stacktrace_printer.cc + sanitizer_symbolizer.cc + sanitizer_symbolizer_fuchsia.cc + sanitizer_symbolizer_libbacktrace.cc + sanitizer_symbolizer_libcdep.cc + sanitizer_symbolizer_mac.cc + sanitizer_symbolizer_posix_libcdep.cc + sanitizer_symbolizer_report.cc + sanitizer_symbolizer_win.cc + sanitizer_unwind_linux_libcdep.cc + sanitizer_unwind_win.cc) + # Explicitly list all sanitizer_common headers. Not all of these are # included in sanitizer_common source files, but we need to depend on # headers when building our custom unit tests. @@ -217,6 +220,12 @@ add_compiler_rt_object_libraries(RTSanitizerCommonCoverage SOURCES ${SANITIZER_COVERAGE_SOURCES} CFLAGS ${SANITIZER_CFLAGS} DEFS ${SANITIZER_COMMON_DEFINITIONS}) +add_compiler_rt_object_libraries(RTSanitizerCommonSymbolizer + ${OS_OPTION} + ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} + SOURCES ${SANITIZER_SYMBOLIZER_SOURCES} + CFLAGS ${SANITIZER_CFLAGS} + DEFS ${SANITIZER_COMMON_DEFINITIONS}) set(SANITIZER_NO_WEAK_HOOKS_CFLAGS ${SANITIZER_CFLAGS}) list(APPEND SANITIZER_NO_WEAK_HOOKS_CFLAGS "-DSANITIZER_SUPPORTS_WEAK_HOOKS=0") diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.cc b/compiler-rt/lib/sanitizer_common/sanitizer_common.cc index ae26d5efc24..04e3dd7f788 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.cc @@ -17,8 +17,6 @@ #include "sanitizer_flags.h" #include "sanitizer_libc.h" #include "sanitizer_placement_new.h" -#include "sanitizer_stacktrace_printer.h" -#include "sanitizer_symbolizer.h" namespace __sanitizer { @@ -107,18 +105,6 @@ void ReportErrorSummary(const char *error_message, const char *alt_tool_name) { __sanitizer_report_error_summary(buff.data()); } -#if !SANITIZER_GO -void ReportErrorSummary(const char *error_type, const AddressInfo &info, - const char *alt_tool_name) { - if (!common_flags()->print_summary) return; - InternalScopedString buff(kMaxSummaryLength); - buff.append("%s ", error_type); - RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style, - common_flags()->strip_path_prefix); - ReportErrorSummary(buff.data(), alt_tool_name); -} -#endif - // Removes the ANSI escape sequences from the input string (in-place). void RemoveANSIEscapeSequencesFromString(char *str) { if (!str) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc index 5e56e31fe6a..796a054858b 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -11,100 +11,14 @@ // run-time libraries. //===----------------------------------------------------------------------===// -#include "sanitizer_common.h" - #include "sanitizer_allocator_interface.h" -#include "sanitizer_file.h" +#include "sanitizer_common.h" #include "sanitizer_flags.h" #include "sanitizer_procmaps.h" -#include "sanitizer_report_decorator.h" -#include "sanitizer_stacktrace.h" -#include "sanitizer_symbolizer.h" -#if SANITIZER_POSIX -#include "sanitizer_posix.h" -#include <sys/mman.h> -#endif namespace __sanitizer { -#if !SANITIZER_FUCHSIA - -bool ReportFile::SupportsColors() { - SpinMutexLock l(mu); - ReopenIfNecessary(); - return SupportsColoredOutput(fd); -} - -static INLINE bool ReportSupportsColors() { - return report_file.SupportsColors(); -} - -#else // SANITIZER_FUCHSIA - -// Fuchsia's logs always go through post-processing that handles colorization. -static INLINE bool ReportSupportsColors() { return true; } - -#endif // !SANITIZER_FUCHSIA - -bool ColorizeReports() { - // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color - // printing on Windows. - if (SANITIZER_WINDOWS) - return false; - - const char *flag = common_flags()->color; - return internal_strcmp(flag, "always") == 0 || - (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors()); -} - -void ReportErrorSummary(const char *error_type, const StackTrace *stack, - const char *alt_tool_name) { -#if !SANITIZER_GO - if (!common_flags()->print_summary) - return; - if (stack->size == 0) { - ReportErrorSummary(error_type); - return; - } - // Currently, we include the first stack frame into the report summary. - // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). - uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); - SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); - ReportErrorSummary(error_type, frame->info, alt_tool_name); - frame->ClearAll(); -#endif -} - -void ReportMmapWriteExec(int prot) { -#if SANITIZER_POSIX && (!SANITIZER_GO && !SANITIZER_ANDROID) - if ((prot & (PROT_WRITE | PROT_EXEC)) != (PROT_WRITE | PROT_EXEC)) - return; - - ScopedErrorReportLock l; - SanitizerCommonDecorator d; - - InternalScopedBuffer<BufferedStackTrace> stack_buffer(1); - BufferedStackTrace *stack = stack_buffer.data(); - stack->Reset(); - uptr top = 0; - uptr bottom = 0; - GET_CALLER_PC_BP_SP; - (void)sp; - bool fast = common_flags()->fast_unwind_on_fatal; - if (fast) - GetThreadStackTopAndBottom(false, &top, &bottom); - stack->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, fast); - - Printf("%s", d.Warning()); - Report("WARNING: %s: writable-executable page usage\n", SanitizerToolName); - Printf("%s", d.Default()); - - stack->Print(); - ReportErrorSummary("w-and-x-usage", stack); -#endif -} - static void (*SoftRssLimitExceededCallback)(bool exceeded); void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) { CHECK_EQ(SoftRssLimitExceededCallback, nullptr); @@ -178,127 +92,6 @@ void BackgroundThread(void *arg) { } #endif -#if !SANITIZER_FUCHSIA && !SANITIZER_GO -void StartReportDeadlySignal() { - // Write the first message using fd=2, just in case. - // It may actually fail to write in case stderr is closed. - CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName)); - static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; - CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1); -} - -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 -} - -static void PrintMemoryByte(InternalScopedString *str, const char *before, - u8 byte) { - SanitizerCommonDecorator d; - str->append("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15, - d.Default()); -} - -static void MaybeDumpInstructionBytes(uptr pc) { - if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) - return; - InternalScopedString str(1024); - str.append("First 16 instruction bytes at pc: "); - if (IsAccessibleMemoryRange(pc, 16)) { - for (int i = 0; i < 16; ++i) { - PrintMemoryByte(&str, "", ((u8 *)pc)[i]); - } - str.append("\n"); - } else { - str.append("unaccessible\n"); - } - Report("%s", str.data()); -} - -static void MaybeDumpRegisters(void *context) { - if (!common_flags()->dump_registers) return; - SignalContext::DumpAllRegisters(context); -} - -static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid, - UnwindSignalStackCallbackType unwind, - const void *unwind_context) { - 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.Default()); - InternalScopedBuffer<BufferedStackTrace> stack_buffer(1); - BufferedStackTrace *stack = stack_buffer.data(); - stack->Reset(); - unwind(sig, unwind_context, stack); - stack->Print(); - ReportErrorSummary(kDescription, stack); -} - -static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid, - UnwindSignalStackCallbackType unwind, - const void *unwind_context) { - SanitizerCommonDecorator d; - Printf("%s", d.Warning()); - const char *description = sig.Describe(); - 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.Default()); - 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); - InternalScopedBuffer<BufferedStackTrace> stack_buffer(1); - BufferedStackTrace *stack = stack_buffer.data(); - stack->Reset(); - unwind(sig, unwind_context, stack); - stack->Print(); - MaybeDumpInstructionBytes(sig.pc); - MaybeDumpRegisters(sig.context); - Printf("%s can not provide additional info.\n", SanitizerToolName); - ReportErrorSummary(description, stack); -} - -void ReportDeadlySignal(const SignalContext &sig, u32 tid, - UnwindSignalStackCallbackType unwind, - const void *unwind_context) { - if (sig.IsStackOverflow()) - ReportStackOverflowImpl(sig, tid, unwind, unwind_context); - else - ReportDeadlySignalImpl(sig, tid, unwind, unwind_context); -} - -void HandleDeadlySignal(void *siginfo, void *context, u32 tid, - UnwindSignalStackCallbackType unwind, - const void *unwind_context) { - StartReportDeadlySignal(); - ScopedErrorReportLock rl; - SignalContext sig(siginfo, context); - ReportDeadlySignal(sig, tid, unwind, unwind_context); - Report("ABORTING\n"); - Die(); -} - -#endif // !SANITIZER_FUCHSIA && !SANITIZER_GO - void WriteToSyslog(const char *msg) { InternalScopedString msg_copy(kErrorMessageBufferSize); msg_copy.append("%s", msg); @@ -329,47 +122,6 @@ void MaybeStartBackgroudThread() { #endif } -static atomic_uintptr_t reporting_thread = {0}; -static StaticSpinMutex CommonSanitizerReportMutex; - -ScopedErrorReportLock::ScopedErrorReportLock() { - uptr current = GetThreadSelf(); - for (;;) { - uptr expected = 0; - if (atomic_compare_exchange_strong(&reporting_thread, &expected, current, - memory_order_relaxed)) { - // We've claimed reporting_thread so proceed. - CommonSanitizerReportMutex.Lock(); - return; - } - - if (expected == current) { - // This is either asynch signal or nested error during error reporting. - // Fail simple to avoid deadlocks in Report(). - - // Can't use Report() here because of potential deadlocks in nested - // signal handlers. - CatastrophicErrorWrite(SanitizerToolName, - internal_strlen(SanitizerToolName)); - static const char msg[] = ": nested bug in the same thread, aborting.\n"; - CatastrophicErrorWrite(msg, sizeof(msg) - 1); - - internal__exit(common_flags()->exitcode); - } - - internal_sched_yield(); - } -} - -ScopedErrorReportLock::~ScopedErrorReportLock() { - CommonSanitizerReportMutex.Unlock(); - atomic_store_relaxed(&reporting_thread, 0); -} - -void ScopedErrorReportLock::CheckLocked() { - CommonSanitizerReportMutex.CheckLocked(); -} - static void (*sandboxing_callback)(); void SetSandboxingCallback(void (*f)()) { sandboxing_callback = f; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc index f1b63cbd124..86d37f9eb06 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc @@ -1,11 +1,11 @@ -//===-- sanitizer_coverage_fuchsia.cc ------------------------------------===// +//===-- sanitizer_coverage_fuchsia.cc -------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // // Sanitizer Coverage Controller for Trace PC Guard, Fuchsia-specific version. // diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index 3c5f29b2899..8a41d235c4d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -16,7 +16,6 @@ #include "sanitizer_atomic.h" #include "sanitizer_common.h" #include "sanitizer_file.h" -#include "sanitizer_symbolizer.h" using namespace __sanitizer; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cc b/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cc index a4a51f1daac..11b29c6e736 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cc @@ -1,16 +1,16 @@ -//===-- sanitizer_fuchsia.cc ---------------------------------------------===// +//===-- sanitizer_fuchsia.cc ----------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// // // This file is shared between AddressSanitizer and other sanitizer // run-time libraries and implements Fuchsia-specific functions from // sanitizer_common.h. -//===---------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// #include "sanitizer_fuchsia.h" #if SANITIZER_FUCHSIA @@ -18,13 +18,11 @@ #include "sanitizer_common.h" #include "sanitizer_libc.h" #include "sanitizer_mutex.h" -#include "sanitizer_stacktrace.h" #include <limits.h> #include <pthread.h> #include <stdlib.h> #include <unistd.h> -#include <unwind.h> #include <zircon/errors.h> #include <zircon/process.h> #include <zircon/syscalls.h> @@ -92,10 +90,6 @@ void MaybeReexec() {} void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {} void DisableCoreDumperIfNecessary() {} void InstallDeadlySignalHandlers(SignalHandlerType handler) {} -void StartReportDeadlySignal() {} -void ReportDeadlySignal(const SignalContext &sig, u32 tid, - UnwindSignalStackCallbackType unwind, - const void *unwind_context) {} void SetAlternateSignalStack() {} void UnsetAlternateSignalStack() {} void InitTlsSize() {} @@ -106,42 +100,6 @@ bool SignalContext::IsStackOverflow() const { return false; } void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); } const char *SignalContext::Describe() const { UNIMPLEMENTED(); } -struct UnwindTraceArg { - BufferedStackTrace *stack; - u32 max_depth; -}; - -_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { - UnwindTraceArg *arg = static_cast<UnwindTraceArg *>(param); - CHECK_LT(arg->stack->size, arg->max_depth); - uptr pc = _Unwind_GetIP(ctx); - if (pc < PAGE_SIZE) return _URC_NORMAL_STOP; - arg->stack->trace_buffer[arg->stack->size++] = pc; - return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP - : _URC_NO_REASON); -} - -void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) { - CHECK_GE(max_depth, 2); - size = 0; - UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; - _Unwind_Backtrace(Unwind_Trace, &arg); - CHECK_GT(size, 0); - // We need to pop a few frames so that pc is on top. - uptr to_pop = LocatePcInTrace(pc); - // trace_buffer[0] belongs to the current function so we always pop it, - // unless there is only 1 frame in the stack trace (1 frame is always better - // than 0!). - PopStackFrames(Min(to_pop, static_cast<uptr>(1))); - trace_buffer[0] = pc; -} - -void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, - u32 max_depth) { - CHECK_NE(context, nullptr); - UNREACHABLE("signal context doesn't exist"); -} - enum MutexState : int { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 }; BlockingMutex::BlockingMutex() { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc index 8585e266168..06696181ef1 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc @@ -14,7 +14,7 @@ #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ SANITIZER_OPENBSD || SANITIZER_SOLARIS #include "sanitizer_common.h" @@ -26,8 +26,6 @@ #include "sanitizer_mutex.h" #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" -#include "sanitizer_stacktrace.h" -#include "sanitizer_symbolizer.h" #if SANITIZER_LINUX #include <asm/param.h> diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc index a5980edd0ae..8647724f2e4 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -26,7 +26,6 @@ #include "sanitizer_linux.h" #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" -#include "sanitizer_stacktrace.h" #include <dlfcn.h> // for dlsym() #include <link.h> diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc index 0a0f63866f6..ad0b4d0ea0b 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cc @@ -21,7 +21,6 @@ #include "sanitizer_libc.h" #include "sanitizer_posix.h" #include "sanitizer_procmaps.h" -#include "sanitizer_stacktrace.h" #include <errno.h> #include <fcntl.h> diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc index 3d1117d9d3c..3a1227e9c6c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.cc @@ -16,8 +16,12 @@ #if SANITIZER_FUCHSIA #include "sanitizer_fuchsia.h" +#include "sanitizer_stacktrace.h" #include "sanitizer_symbolizer.h" +#include <limits.h> +#include <unwind.h> + namespace __sanitizer { // For Fuchsia we don't do any actual symbolization per se. @@ -102,6 +106,47 @@ Symbolizer *Symbolizer::PlatformInit() { void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } +void StartReportDeadlySignal() {} +void ReportDeadlySignal(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) {} + +struct UnwindTraceArg { + BufferedStackTrace *stack; + u32 max_depth; +}; + +_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { + UnwindTraceArg *arg = static_cast<UnwindTraceArg *>(param); + CHECK_LT(arg->stack->size, arg->max_depth); + uptr pc = _Unwind_GetIP(ctx); + if (pc < PAGE_SIZE) return _URC_NORMAL_STOP; + arg->stack->trace_buffer[arg->stack->size++] = pc; + return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP + : _URC_NO_REASON); +} + +void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) { + CHECK_GE(max_depth, 2); + size = 0; + UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; + _Unwind_Backtrace(Unwind_Trace, &arg); + CHECK_GT(size, 0); + // We need to pop a few frames so that pc is on top. + uptr to_pop = LocatePcInTrace(pc); + // trace_buffer[0] belongs to the current function so we always pop it, + // unless there is only 1 frame in the stack trace (1 frame is always better + // than 0!). + PopStackFrames(Min(to_pop, static_cast<uptr>(1))); + trace_buffer[0] = pc; +} + +void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context, + u32 max_depth) { + CHECK_NE(context, nullptr); + UNREACHABLE("signal context doesn't exist"); +} + } // namespace __sanitizer #endif // SANITIZER_FUCHSIA diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cc b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cc new file mode 100644 index 00000000000..1b218336dda --- /dev/null +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cc @@ -0,0 +1,282 @@ +//===-- sanitizer_symbolizer_report.cc ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// This file is shared between AddressSanitizer and other sanitizer run-time +/// libraries and implements symbolized reports related functions. +/// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common.h" +#include "sanitizer_file.h" +#include "sanitizer_flags.h" +#include "sanitizer_procmaps.h" +#include "sanitizer_report_decorator.h" +#include "sanitizer_stacktrace.h" +#include "sanitizer_stacktrace_printer.h" +#include "sanitizer_symbolizer.h" + +#if SANITIZER_POSIX +# include "sanitizer_posix.h" +# include <sys/mman.h> +#endif + +namespace __sanitizer { + +#if !SANITIZER_GO +void ReportErrorSummary(const char *error_type, const AddressInfo &info, + const char *alt_tool_name) { + if (!common_flags()->print_summary) return; + InternalScopedString buff(kMaxSummaryLength); + buff.append("%s ", error_type); + RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style, + common_flags()->strip_path_prefix); + ReportErrorSummary(buff.data(), alt_tool_name); +} +#endif + +#if !SANITIZER_FUCHSIA + +bool ReportFile::SupportsColors() { + SpinMutexLock l(mu); + ReopenIfNecessary(); + return SupportsColoredOutput(fd); +} + +static INLINE bool ReportSupportsColors() { + return report_file.SupportsColors(); +} + +#else // SANITIZER_FUCHSIA + +// Fuchsia's logs always go through post-processing that handles colorization. +static INLINE bool ReportSupportsColors() { return true; } + +#endif // !SANITIZER_FUCHSIA + +bool ColorizeReports() { + // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color + // printing on Windows. + if (SANITIZER_WINDOWS) + return false; + + const char *flag = common_flags()->color; + return internal_strcmp(flag, "always") == 0 || + (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors()); +} + +void ReportErrorSummary(const char *error_type, const StackTrace *stack, + const char *alt_tool_name) { +#if !SANITIZER_GO + if (!common_flags()->print_summary) + return; + if (stack->size == 0) { + ReportErrorSummary(error_type); + return; + } + // Currently, we include the first stack frame into the report summary. + // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). + uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); + SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); + ReportErrorSummary(error_type, frame->info, alt_tool_name); + frame->ClearAll(); +#endif +} + +void ReportMmapWriteExec(int prot) { +#if SANITIZER_POSIX && (!SANITIZER_GO && !SANITIZER_ANDROID) + if ((prot & (PROT_WRITE | PROT_EXEC)) != (PROT_WRITE | PROT_EXEC)) + return; + + ScopedErrorReportLock l; + SanitizerCommonDecorator d; + + InternalScopedBuffer<BufferedStackTrace> stack_buffer(1); + BufferedStackTrace *stack = stack_buffer.data(); + stack->Reset(); + uptr top = 0; + uptr bottom = 0; + GET_CALLER_PC_BP_SP; + (void)sp; + bool fast = common_flags()->fast_unwind_on_fatal; + if (fast) + GetThreadStackTopAndBottom(false, &top, &bottom); + stack->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, fast); + + Printf("%s", d.Warning()); + Report("WARNING: %s: writable-executable page usage\n", SanitizerToolName); + Printf("%s", d.Default()); + + stack->Print(); + ReportErrorSummary("w-and-x-usage", stack); +#endif +} + +#if !SANITIZER_FUCHSIA && !SANITIZER_GO +void StartReportDeadlySignal() { + // Write the first message using fd=2, just in case. + // It may actually fail to write in case stderr is closed. + CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName)); + static const char kDeadlySignal[] = ":DEADLYSIGNAL\n"; + CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1); +} + +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 +} + +static void PrintMemoryByte(InternalScopedString *str, const char *before, + u8 byte) { + SanitizerCommonDecorator d; + str->append("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15, + d.Default()); +} + +static void MaybeDumpInstructionBytes(uptr pc) { + if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) + return; + InternalScopedString str(1024); + str.append("First 16 instruction bytes at pc: "); + if (IsAccessibleMemoryRange(pc, 16)) { + for (int i = 0; i < 16; ++i) { + PrintMemoryByte(&str, "", ((u8 *)pc)[i]); + } + str.append("\n"); + } else { + str.append("unaccessible\n"); + } + Report("%s", str.data()); +} + +static void MaybeDumpRegisters(void *context) { + if (!common_flags()->dump_registers) return; + SignalContext::DumpAllRegisters(context); +} + +static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + 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.Default()); + InternalScopedBuffer<BufferedStackTrace> stack_buffer(1); + BufferedStackTrace *stack = stack_buffer.data(); + stack->Reset(); + unwind(sig, unwind_context, stack); + stack->Print(); + ReportErrorSummary(kDescription, stack); +} + +static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + SanitizerCommonDecorator d; + Printf("%s", d.Warning()); + const char *description = sig.Describe(); + 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.Default()); + 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); + InternalScopedBuffer<BufferedStackTrace> stack_buffer(1); + BufferedStackTrace *stack = stack_buffer.data(); + stack->Reset(); + unwind(sig, unwind_context, stack); + stack->Print(); + MaybeDumpInstructionBytes(sig.pc); + MaybeDumpRegisters(sig.context); + Printf("%s can not provide additional info.\n", SanitizerToolName); + ReportErrorSummary(description, stack); +} + +void ReportDeadlySignal(const SignalContext &sig, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + if (sig.IsStackOverflow()) + ReportStackOverflowImpl(sig, tid, unwind, unwind_context); + else + ReportDeadlySignalImpl(sig, tid, unwind, unwind_context); +} + +void HandleDeadlySignal(void *siginfo, void *context, u32 tid, + UnwindSignalStackCallbackType unwind, + const void *unwind_context) { + StartReportDeadlySignal(); + ScopedErrorReportLock rl; + SignalContext sig(siginfo, context); + ReportDeadlySignal(sig, tid, unwind, unwind_context); + Report("ABORTING\n"); + Die(); +} + +#endif // !SANITIZER_FUCHSIA && !SANITIZER_GO + +static atomic_uintptr_t reporting_thread = {0}; +static StaticSpinMutex CommonSanitizerReportMutex; + +ScopedErrorReportLock::ScopedErrorReportLock() { + uptr current = GetThreadSelf(); + for (;;) { + uptr expected = 0; + if (atomic_compare_exchange_strong(&reporting_thread, &expected, current, + memory_order_relaxed)) { + // We've claimed reporting_thread so proceed. + CommonSanitizerReportMutex.Lock(); + return; + } + + if (expected == current) { + // This is either asynch signal or nested error during error reporting. + // Fail simple to avoid deadlocks in Report(). + + // Can't use Report() here because of potential deadlocks in nested + // signal handlers. + CatastrophicErrorWrite(SanitizerToolName, + internal_strlen(SanitizerToolName)); + static const char msg[] = ": nested bug in the same thread, aborting.\n"; + CatastrophicErrorWrite(msg, sizeof(msg) - 1); + + internal__exit(common_flags()->exitcode); + } + + internal_sched_yield(); + } +} + +ScopedErrorReportLock::~ScopedErrorReportLock() { + CommonSanitizerReportMutex.Unlock(); + atomic_store_relaxed(&reporting_thread, 0); +} + +void ScopedErrorReportLock::CheckLocked() { + CommonSanitizerReportMutex.CheckLocked(); +} + +} // namespace __sanitizer diff --git a/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt index 1bccaa78f39..9f2cb39fb53 100644 --- a/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt +++ b/compiler-rt/lib/sanitizer_common/tests/CMakeLists.txt @@ -178,7 +178,8 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID) if(APPLE) add_sanitizer_common_lib("RTSanitizerCommon.test.osx" $<TARGET_OBJECTS:RTSanitizerCommon.osx> - $<TARGET_OBJECTS:RTSanitizerCommonLibc.osx>) + $<TARGET_OBJECTS:RTSanitizerCommonLibc.osx> + $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.osx>) else() if(CAN_TARGET_x86_64) add_sanitizer_common_lib("RTSanitizerCommon.test.nolibc.x86_64" @@ -188,7 +189,8 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID) foreach(arch ${SANITIZER_UNITTEST_SUPPORTED_ARCH}) add_sanitizer_common_lib("RTSanitizerCommon.test.${arch}" $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> - $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>) + $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> + $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>) endforeach() endif() foreach(arch ${SANITIZER_UNITTEST_SUPPORTED_ARCH}) @@ -202,7 +204,8 @@ if(ANDROID) ${SANITIZER_UNITTESTS} ${COMPILER_RT_GTEST_SOURCE} $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> - $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>) + $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> + $<TARGET_OBJECTS:RTSanitizerCommonSymbolizer.${arch}>) set_target_compile_flags(SanitizerTest ${SANITIZER_COMMON_CFLAGS} ${SANITIZER_TEST_CFLAGS_COMMON}) |

