| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include "catch_fatal_condition.h" |
| |
|
| | #include "catch_context.h" |
| | #include "catch_enforce.h" |
| | #include "catch_run_context.h" |
| | #include "catch_windows_h_proxy.h" |
| |
|
| | #include <algorithm> |
| |
|
| | #if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS ) |
| |
|
| | namespace Catch { |
| |
|
| | |
| | |
| | void FatalConditionHandler::engage_platform() {} |
| | void FatalConditionHandler::disengage_platform() {} |
| | FatalConditionHandler::FatalConditionHandler() = default; |
| | FatalConditionHandler::~FatalConditionHandler() = default; |
| |
|
| | } |
| |
|
| | #endif |
| |
|
| | #if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS ) |
| | #error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time" |
| | #endif |
| |
|
| | #if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) |
| |
|
| | namespace { |
| | |
| | void reportFatal( char const * const message ) { |
| | Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); |
| | } |
| |
|
| | |
| | |
| | |
| | constexpr std::size_t minStackSizeForErrors = 32 * 1024; |
| | } |
| |
|
| | #endif |
| |
|
| | #if defined( CATCH_CONFIG_WINDOWS_SEH ) |
| |
|
| | namespace Catch { |
| |
|
| | struct SignalDefs { DWORD id; const char* name; }; |
| |
|
| | |
| | |
| | |
| | static SignalDefs signalDefs[] = { |
| | { static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION), "SIGILL - Illegal instruction signal" }, |
| | { static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow" }, |
| | { static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal" }, |
| | { static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" }, |
| | }; |
| |
|
| | static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { |
| | for (auto const& def : signalDefs) { |
| | if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { |
| | reportFatal(def.name); |
| | } |
| | } |
| | |
| | |
| | return EXCEPTION_CONTINUE_SEARCH; |
| | } |
| |
|
| | |
| | |
| | |
| | static PVOID exceptionHandlerHandle = nullptr; |
| |
|
| |
|
| | |
| | |
| | FatalConditionHandler::FatalConditionHandler() { |
| | ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors); |
| | if (!SetThreadStackGuarantee(&guaranteeSize)) { |
| | |
| | |
| | Catch::cerr() |
| | << "Failed to reserve piece of stack." |
| | << " Stack overflows will not be reported successfully."; |
| | } |
| | } |
| |
|
| | |
| | |
| | FatalConditionHandler::~FatalConditionHandler() = default; |
| |
|
| |
|
| | void FatalConditionHandler::engage_platform() { |
| | |
| | exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); |
| | if (!exceptionHandlerHandle) { |
| | CATCH_RUNTIME_ERROR("Could not register vectored exception handler"); |
| | } |
| | } |
| |
|
| | void FatalConditionHandler::disengage_platform() { |
| | if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) { |
| | CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler"); |
| | } |
| | exceptionHandlerHandle = nullptr; |
| | } |
| |
|
| | } |
| |
|
| | #endif |
| |
|
| | #if defined( CATCH_CONFIG_POSIX_SIGNALS ) |
| |
|
| | #include <signal.h> |
| |
|
| | namespace Catch { |
| |
|
| | struct SignalDefs { |
| | int id; |
| | const char* name; |
| | }; |
| |
|
| | static SignalDefs signalDefs[] = { |
| | { SIGINT, "SIGINT - Terminal interrupt signal" }, |
| | { SIGILL, "SIGILL - Illegal instruction signal" }, |
| | { SIGFPE, "SIGFPE - Floating point error signal" }, |
| | { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, |
| | { SIGTERM, "SIGTERM - Termination request signal" }, |
| | { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } |
| | }; |
| |
|
| | |
| | |
| | |
| | #if defined(__GNUC__) |
| | # pragma GCC diagnostic push |
| | # pragma GCC diagnostic ignored "-Wmissing-field-initializers" |
| | #endif |
| |
|
| | static char* altStackMem = nullptr; |
| | static std::size_t altStackSize = 0; |
| | static stack_t oldSigStack{}; |
| | static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{}; |
| |
|
| | static void restorePreviousSignalHandlers() { |
| | |
| | |
| | |
| | |
| | for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { |
| | sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); |
| | } |
| | |
| | sigaltstack(&oldSigStack, nullptr); |
| | } |
| |
|
| | static void handleSignal( int sig ) { |
| | char const * name = "<unknown signal>"; |
| | for (auto const& def : signalDefs) { |
| | if (sig == def.id) { |
| | name = def.name; |
| | break; |
| | } |
| | } |
| | |
| | |
| | |
| | restorePreviousSignalHandlers(); |
| | reportFatal( name ); |
| | raise( sig ); |
| | } |
| |
|
| | FatalConditionHandler::FatalConditionHandler() { |
| | assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists"); |
| | if (altStackSize == 0) { |
| | altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors); |
| | } |
| | altStackMem = new char[altStackSize](); |
| | } |
| |
|
| | FatalConditionHandler::~FatalConditionHandler() { |
| | delete[] altStackMem; |
| | |
| | |
| | altStackMem = nullptr; |
| | } |
| |
|
| | void FatalConditionHandler::engage_platform() { |
| | stack_t sigStack; |
| | sigStack.ss_sp = altStackMem; |
| | sigStack.ss_size = altStackSize; |
| | sigStack.ss_flags = 0; |
| | sigaltstack(&sigStack, &oldSigStack); |
| | struct sigaction sa = { }; |
| |
|
| | sa.sa_handler = handleSignal; |
| | sa.sa_flags = SA_ONSTACK; |
| | for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { |
| | sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); |
| | } |
| | } |
| |
|
| | #if defined(__GNUC__) |
| | # pragma GCC diagnostic pop |
| | #endif |
| |
|
| |
|
| | void FatalConditionHandler::disengage_platform() { |
| | restorePreviousSignalHandlers(); |
| | } |
| |
|
| | } |
| |
|
| | #endif |
| |
|