123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- #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
|