summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/catch/include/internal/catch_fatal_condition.hpp
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2017-02-05 15:45:26 +0100
committer Miodrag Milanovic <mmicko@gmail.com>2017-02-05 15:46:07 +0100
commit02c97cd0f7c4d630f1a90f9f2626746e47a28c09 (patch)
tree2b48d051a55f2b65525824546cd9fcf9e05907cf /3rdparty/catch/include/internal/catch_fatal_condition.hpp
parentd20b4ba6864b45d0c068d98d43e63c8bc5014a3b (diff)
Updated Catch to latest (nw)
Diffstat (limited to '3rdparty/catch/include/internal/catch_fatal_condition.hpp')
-rw-r--r--3rdparty/catch/include/internal/catch_fatal_condition.hpp132
1 files changed, 109 insertions, 23 deletions
diff --git a/3rdparty/catch/include/internal/catch_fatal_condition.hpp b/3rdparty/catch/include/internal/catch_fatal_condition.hpp
index dd21d5904bd..29021a392cb 100644
--- a/3rdparty/catch/include/internal/catch_fatal_condition.hpp
+++ b/3rdparty/catch/include/internal/catch_fatal_condition.hpp
@@ -12,25 +12,75 @@
namespace Catch {
- // Report the error condition then exit the process
- inline void fatal( std::string const& message, int exitCode ) {
+ // Report the error condition
+ inline void reportFatal( std::string const& message ) {
IContext& context = Catch::getCurrentContext();
IResultCapture* resultCapture = context.getResultCapture();
resultCapture->handleFatalErrorCondition( message );
-
- if( Catch::alwaysTrue() ) // avoids "no return" warnings
- exit( exitCode );
}
} // namespace Catch
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
+
+#include "catch_windows_h_proxy.h"
+
+
namespace Catch {
+ struct SignalDefs { DWORD id; const char* name; };
+ extern SignalDefs signalDefs[];
+ // 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.
+ SignalDefs signalDefs[] = {
+ { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
+ { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
+ { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
+ { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
+ };
+
struct FatalConditionHandler {
- void reset() {}
- };
+
+ static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
+ for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
+ if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) {
+ reportFatal(signalDefs[i].name);
+ }
+ }
+ // If its not an exception we care about, pass it along.
+ // This stops us from eating debugger breaks etc.
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+
+ // 32k seems enough for Catch to handle stack overflow,
+ // but the value was found experimentally, so there is no strong guarantee
+ FatalConditionHandler():m_isSet(true), m_guaranteeSize(32 * 1024), m_exceptionHandlerHandle(CATCH_NULL) {
+ // Register as first handler in current chain
+ m_exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
+ // Pass in guarantee size to be filled
+ SetThreadStackGuarantee(&m_guaranteeSize);
+ }
+
+ void reset() {
+ if (m_isSet) {
+ // Unregister handler and restore the old guarantee
+ RemoveVectoredExceptionHandler(m_exceptionHandlerHandle);
+ SetThreadStackGuarantee(&m_guaranteeSize);
+ m_exceptionHandlerHandle = CATCH_NULL;
+ m_isSet = false;
+ }
+ }
+
+ ~FatalConditionHandler() {
+ reset();
+ }
+ private:
+ bool m_isSet;
+ ULONG m_guaranteeSize;
+ PVOID m_exceptionHandlerHandle;
+ };
} // namespace Catch
@@ -40,7 +90,10 @@ namespace Catch {
namespace Catch {
- struct SignalDefs { int id; const char* name; };
+ struct SignalDefs {
+ int id;
+ const char* name;
+ };
extern SignalDefs signalDefs[];
SignalDefs signalDefs[] = {
{ SIGINT, "SIGINT - Terminal interrupt signal" },
@@ -49,35 +102,68 @@ namespace Catch {
{ SIGSEGV, "SIGSEGV - Segmentation violation signal" },
{ SIGTERM, "SIGTERM - Termination request signal" },
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
- };
+ };
struct FatalConditionHandler {
+ static bool isSet;
+ static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)];
+ static stack_t oldSigStack;
+ static char altStackMem[SIGSTKSZ];
+
static void handleSignal( int sig ) {
- for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
- if( sig == signalDefs[i].id )
- fatal( signalDefs[i].name, -sig );
- fatal( "<unknown signal>", -sig );
+ std::string name = "<unknown signal>";
+ for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
+ SignalDefs &def = signalDefs[i];
+ if (sig == def.id) {
+ name = def.name;
+ break;
+ }
+ }
+ reset();
+ reportFatal(name);
+ raise( sig );
}
- FatalConditionHandler() : m_isSet( true ) {
- for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
- signal( signalDefs[i].id, handleSignal );
+ FatalConditionHandler() {
+ isSet = true;
+ stack_t sigStack;
+ sigStack.ss_sp = altStackMem;
+ sigStack.ss_size = SIGSTKSZ;
+ sigStack.ss_flags = 0;
+ sigaltstack(&sigStack, &oldSigStack);
+ struct sigaction sa = { 0 };
+
+ 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]);
+ }
}
+
+
~FatalConditionHandler() {
reset();
}
- void reset() {
- if( m_isSet ) {
- for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i )
- signal( signalDefs[i].id, SIG_DFL );
- m_isSet = false;
+ static void reset() {
+ if( isSet ) {
+ // Set signals back to previous values -- hopefully nobody overwrote them in the meantime
+ for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
+ sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL);
+ }
+ // Return the old stack
+ sigaltstack(&oldSigStack, CATCH_NULL);
+ isSet = false;
}
}
-
- bool m_isSet;
};
+ bool FatalConditionHandler::isSet = false;
+ struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
+ stack_t FatalConditionHandler::oldSigStack = {};
+ char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
+
+
} // namespace Catch
#endif // not Windows