diff --git a/Fleece/Support/Backtrace+signals-posix.cc b/Fleece/Support/Backtrace+signals-posix.cc index a88c59ca..a59235a8 100644 --- a/Fleece/Support/Backtrace+signals-posix.cc +++ b/Fleece/Support/Backtrace+signals-posix.cc @@ -62,9 +62,10 @@ namespace fleece { for ( const int signal : signals) { struct sigaction action{}; - action.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER | SA_RESETHAND; + // NOTE: No SA_RESETHAND since on managed platforms signals are recoverable and + // we want our handler to keep working in the event that they are not + action.sa_flags = SA_SIGINFO | SA_ONSTACK; sigfillset(&action.sa_mask); - sigdelset(&action.sa_mask, signal); #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdisabled-macro-expansion" @@ -91,11 +92,11 @@ namespace fleece { unique_ptr _stack_content; #ifdef __APPLE__ - static constexpr array signals = { -#else static constexpr array signals = { +#else + static constexpr array signals = { #endif - SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGQUIT, SIGSEGV, SIGSYS, SIGTRAP, SIGXCPU, SIGXFSZ, + SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGQUIT, SIGSEGV, SIGSYS, SIGTRAP, SIGXFSZ, #if defined(__APPLE__) SIGEMT, #endif @@ -111,37 +112,41 @@ namespace fleece { NOINLINE static void crash_handler_immediate(siginfo_t* info, void* context) { void* buffer[50]; int n = Backtrace::raw_capture(buffer, 50, context); - const char* name = strsignal(info->si_signo); - write_to_and_stderr(sLogFD, "\n\n******************** Process Crash: ", 38); - if ( name ) { - write_to_and_stderr(sLogFD, name); - } else { - write_to_and_stderr(sLogFD, "Signal: ", 8); - write_long(info->si_signo, sLogFD); - } + write_to_and_stderr(sLogFD, "\n\n******************** Signal caught: ", 38); + write_long(info->si_signo, sLogFD); write_to_and_stderr(sLogFD, " Timestamp: ", 12); - char timestamp[20]; - snprintf(timestamp, 20, "%lld", static_cast(time(nullptr))); write_long(time(nullptr), sLogFD); write_to_and_stderr(sLogFD, " *******************\n", 21); Backtrace::writeTo(buffer + 3, n - 3, sLogFD); - write_to_and_stderr(sLogFD, "\n******************** Now terminating ********************\n", 59); if ( sLogFD != -1 ) { fsync(sLogFD); - close(sLogFD); } } - [[noreturn]] static void sig_handler(int signo, siginfo_t* info, void* context) { - crash_handler_immediate(info, context); - - auto default_action = BacktraceSignalHandlerPosix::defaultActionFor(signo); - sigaction(signo, &default_action, nullptr); - raise(signo); + static void chain_to_previous(int signo, siginfo_t* info, void* context) { + const auto& prev = defaultActionFor(signo); + if ((prev.sa_flags & SA_SIGINFO) && prev.sa_sigaction && prev.sa_sigaction != &sig_handler) { + // Original fault context: the runtime can recover (and modify *context, + // which our return then resumes into) or die inside this call. + prev.sa_sigaction(signo, info, context); + } else if (prev.sa_handler && prev.sa_handler != SIG_IGN + && prev.sa_handler != SIG_DFL) { + // SIG_IGN and SIG_DFL are not actual functions, don't try to call them + prev.sa_handler(signo); + } else if (prev.sa_handler == SIG_DFL) { + sigaction(signo, &prev, nullptr); // restore default and let it act + raise(signo); // fatal default terminates here + } + //SIG_IGN means ignore, so do just that + } - _exit(128 + signo); + static void sig_handler(int signo, siginfo_t* info, void* context) { + crash_handler_immediate(info, context); + chain_to_previous(signo, info, context); + write_to_and_stderr(sLogFD, + "\n********** Signal handled; execution continuing **********\n", 60); } }; diff --git a/cmake/platform_linux.cmake b/cmake/platform_linux.cmake index 6f885ec8..af2afa4f 100644 --- a/cmake/platform_linux.cmake +++ b/cmake/platform_linux.cmake @@ -1,19 +1,16 @@ include("${CMAKE_CURRENT_LIST_DIR}/platform_base.cmake") include(CheckCXXSourceCompiles) -# libbacktrace is bundled inside GCC's private library directory. -# Ask GCC where it keeps the library and header so that builds with -# other compilers (e.g. Clang) can find it. -find_program(_gcc NAMES gcc) -if(_gcc) +# Both GCC and Clang support -print-file-name to locate bundled libraries. +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") execute_process( - COMMAND ${_gcc} -print-file-name=libbacktrace.a - OUTPUT_VARIABLE _gcc_bt_lib OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) - if(_gcc_bt_lib AND NOT _gcc_bt_lib STREQUAL "libbacktrace.a") - get_filename_component(_gcc_lib_dir "${_gcc_bt_lib}" DIRECTORY) - find_path(BACKTRACE_INCLUDE_DIR backtrace.h HINTS "${_gcc_lib_dir}/include") + COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=libbacktrace.a + OUTPUT_VARIABLE _bt_lib OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET) + if(_bt_lib AND NOT _bt_lib STREQUAL "libbacktrace.a") + get_filename_component(_bt_lib_dir "${_bt_lib}" DIRECTORY) + find_path(BACKTRACE_INCLUDE_DIR backtrace.h HINTS "${_bt_lib_dir}/include") if(BACKTRACE_INCLUDE_DIR) - set(BACKTRACE_LIBRARY "${_gcc_bt_lib}") + set(BACKTRACE_LIBRARY "${_bt_lib}") set(CMAKE_REQUIRED_INCLUDES "${BACKTRACE_INCLUDE_DIR}") set(CMAKE_REQUIRED_LIBRARIES "${BACKTRACE_LIBRARY}") check_cxx_source_compiles(" @@ -26,11 +23,10 @@ if(_gcc) unset(CMAKE_REQUIRED_INCLUDES) unset(CMAKE_REQUIRED_LIBRARIES) endif() + unset(_bt_lib_dir) endif() - unset(_gcc_bt_lib) - unset(_gcc_lib_dir) + unset(_bt_lib) endif() -unset(_gcc) function(set_source_files) set(oneValueArgs RESULT)