| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 | 
							- /*
 
-  *  Created by Phil on 21/08/2014
 
-  *  Copyright 2014 Two Blue Cubes Ltd. All rights reserved.
 
-  *
 
-  *  Distributed under the Boost Software License, Version 1.0. (See accompanying
 
-  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
-  *
 
-  */
 
- /** \file
 
-  * This file provides platform specific implementations of FatalConditionHandler
 
-  *
 
-  * This means that there is a lot of conditional compilation, and platform
 
-  * specific code. Currently, Catch2 supports a dummy handler (if no
 
-  * handler is desired), and 2 platform specific handlers:
 
-  *  * Windows' SEH
 
-  *  * POSIX signals
 
-  *
 
-  * Consequently, various pieces of code below are compiled if either of
 
-  * the platform specific handlers is enabled, or if none of them are
 
-  * enabled. It is assumed that both cannot be enabled at the same time,
 
-  * and doing so should cause a compilation error.
 
-  *
 
-  * If another platform specific handler is added, the compile guards
 
-  * below will need to be updated taking these assumptions into account.
 
-  */
 
- #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 {
 
-     // If neither SEH nor signal handling is required, the handler impls
 
-     // do not have to do anything, and can be empty.
 
-     void FatalConditionHandler::engage_platform() {}
 
-     void FatalConditionHandler::disengage_platform() {}
 
-     FatalConditionHandler::FatalConditionHandler() = default;
 
-     FatalConditionHandler::~FatalConditionHandler() = default;
 
- } // end namespace Catch
 
- #endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS
 
- #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 // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS
 
- #if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
 
- namespace {
 
-     //! Signals fatal error message to the run context
 
-     void reportFatal( char const * const message ) {
 
-         Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
 
-     }
 
-     //! Minimal size Catch2 needs for its own fatal error handling.
 
-     //! Picked anecdotally, so it might not be sufficient on all
 
-     //! platforms, and for all configurations.
 
-     constexpr std::size_t minStackSizeForErrors = 32 * 1024;
 
- } // end unnamed namespace
 
- #endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS
 
- #if defined( CATCH_CONFIG_WINDOWS_SEH )
 
- namespace Catch {
 
-     struct SignalDefs { DWORD id; const char* name; };
 
-     // There is no 1-1 mapping between signals and windows exceptions.
 
-     // Windows can easily distinguish between SO and SigSegV,
 
-     // but SigInt, SigTerm, etc are handled differently.
 
-     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);
 
-             }
 
-         }
 
-         // If its not an exception we care about, pass it along.
 
-         // This stops us from eating debugger breaks etc.
 
-         return EXCEPTION_CONTINUE_SEARCH;
 
-     }
 
-     // Since we do not support multiple instantiations, we put these
 
-     // into global variables and rely on cleaning them up in outlined
 
-     // constructors/destructors
 
-     static PVOID exceptionHandlerHandle = nullptr;
 
-     // For MSVC, we reserve part of the stack memory for handling
 
-     // memory overflow structured exception.
 
-     FatalConditionHandler::FatalConditionHandler() {
 
-         ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);
 
-         if (!SetThreadStackGuarantee(&guaranteeSize)) {
 
-             // We do not want to fully error out, because needing
 
-             // the stack reserve should be rare enough anyway.
 
-             Catch::cerr()
 
-                 << "Failed to reserve piece of stack."
 
-                 << " Stack overflows will not be reported successfully.";
 
-         }
 
-     }
 
-     // We do not attempt to unset the stack guarantee, because
 
-     // Windows does not support lowering the stack size guarantee.
 
-     FatalConditionHandler::~FatalConditionHandler() = default;
 
-     void FatalConditionHandler::engage_platform() {
 
-         // Register as first handler in current chain
 
-         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;
 
-     }
 
- } // end namespace Catch
 
- #endif // CATCH_CONFIG_WINDOWS_SEH
 
- #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" }
 
-     };
 
- // Older GCCs trigger -Wmissing-field-initializers for T foo = {}
 
- // which is zero initialization, but not explicit. We want to avoid
 
- // that.
 
- #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() {
 
-         // We set signal handlers back to the previous ones. Hopefully
 
-         // nobody overwrote them in the meantime, and doesn't expect
 
-         // their signal handlers to live past ours given that they
 
-         // installed them after ours..
 
-         for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
 
-             sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
 
-         }
 
-         // Return the old stack
 
-         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;
 
-             }
 
-         }
 
-         // We need to restore previous signal handlers and let them do
 
-         // their thing, so that the users can have the debugger break
 
-         // when a signal is raised, and so on.
 
-         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;
 
-         // We signal that another instance can be constructed by zeroing
 
-         // out the pointer.
 
-         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();
 
-     }
 
- } // end namespace Catch
 
- #endif // CATCH_CONFIG_POSIX_SIGNALS
 
 
  |