|
|
|
@ -1,6 +1,6 @@ |
|
|
|
|
/*
|
|
|
|
|
* Catch v1.12.2 |
|
|
|
|
* Generated: 2018-05-14 15:10:01.112442 |
|
|
|
|
* Generated: 2023-01-17 08:45:40.979381 |
|
|
|
|
* ---------------------------------------------------------- |
|
|
|
|
* This file has been merged from multiple headers. Please don't edit it directly |
|
|
|
|
* Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. |
|
|
|
@ -214,7 +214,7 @@ |
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
// Use variadic macros if the compiler supports them
|
|
|
|
|
#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ |
|
|
|
|
#if ( defined _MSC_VER && _MSC_VER >= 1400 && !defined __EDGE__) || \ |
|
|
|
|
( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
|
|
|
|
|
( defined __GNUC__ && __GNUC__ >= 3 ) || \
|
|
|
|
|
( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) |
|
|
|
@ -2129,6 +2129,9 @@ namespace Catch{ |
|
|
|
|
#define CATCH_TRAP() \ |
|
|
|
|
__asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
|
|
|
|
|
: : : "memory","r0","r3","r4" ) /* NOLINT */ |
|
|
|
|
#elif defined(__aarch64__) |
|
|
|
|
// Backport of https://github.com/catchorg/Catch2/commit/a25c1a24af8bffd35727a888a307ff0280cf9387
|
|
|
|
|
#define CATCH_TRAP() __asm__(".inst 0xd4200000") |
|
|
|
|
#else |
|
|
|
|
#define CATCH_TRAP() __asm__("int $3\n" : : /* NOLINT */ ) |
|
|
|
|
#endif |
|
|
|
@ -6392,18 +6395,21 @@ CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS |
|
|
|
|
// #included from: catch_fatal_condition.hpp
|
|
|
|
|
#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED |
|
|
|
|
|
|
|
|
|
#include <cassert> |
|
|
|
|
#include <stdexcept> |
|
|
|
|
|
|
|
|
|
namespace Catch { |
|
|
|
|
|
|
|
|
|
// Report the error condition
|
|
|
|
|
inline void reportFatal( std::string const& message ) { |
|
|
|
|
IContext& context = Catch::getCurrentContext(); |
|
|
|
|
IResultCapture* resultCapture = context.getResultCapture(); |
|
|
|
|
resultCapture->handleFatalErrorCondition( message ); |
|
|
|
|
} |
|
|
|
|
//! Signals fatal error message to the run context
|
|
|
|
|
inline void reportFatal(std::string const &message) { |
|
|
|
|
IContext &context = Catch::getCurrentContext(); |
|
|
|
|
IResultCapture *resultCapture = context.getResultCapture(); |
|
|
|
|
resultCapture->handleFatalErrorCondition(message); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} // namespace Catch
|
|
|
|
|
|
|
|
|
|
#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
|
|
|
|
|
#if defined(CATCH_PLATFORM_WINDOWS) /////////////////////////////////////////
|
|
|
|
|
// #included from: catch_windows_h_proxy.h
|
|
|
|
|
|
|
|
|
|
#define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED |
|
|
|
@ -6429,176 +6435,307 @@ namespace Catch { |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# if !defined ( CATCH_CONFIG_WINDOWS_SEH ) |
|
|
|
|
#if !defined(CATCH_CONFIG_WINDOWS_SEH) |
|
|
|
|
|
|
|
|
|
namespace Catch { |
|
|
|
|
struct FatalConditionHandler { |
|
|
|
|
void reset() {} |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
class FatalConditionHandler { |
|
|
|
|
bool m_started; |
|
|
|
|
|
|
|
|
|
// Install/disengage implementation for specific platform.
|
|
|
|
|
// Should be if-defed to work on current platform, can assume
|
|
|
|
|
// engage-disengage 1:1 pairing.
|
|
|
|
|
void engage_platform() {} |
|
|
|
|
void disengage_platform() {} |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
// Should also have platform-specific implementations as needed
|
|
|
|
|
FatalConditionHandler() : m_started(false) {} |
|
|
|
|
~FatalConditionHandler() {} |
|
|
|
|
|
|
|
|
|
void engage() { |
|
|
|
|
assert(!m_started && "Handler cannot be installed twice."); |
|
|
|
|
m_started = true; |
|
|
|
|
engage_platform(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void disengage() { |
|
|
|
|
assert(m_started && |
|
|
|
|
"Handler cannot be uninstalled without being installed first"); |
|
|
|
|
m_started = false; |
|
|
|
|
disengage_platform(); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} // namespace Catch
|
|
|
|
|
|
|
|
|
|
# else // CATCH_CONFIG_WINDOWS_SEH is defined
|
|
|
|
|
#else // CATCH_CONFIG_WINDOWS_SEH is defined
|
|
|
|
|
|
|
|
|
|
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 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 { |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
// 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 = CATCH_NULL; |
|
|
|
|
|
|
|
|
|
FatalConditionHandler() { |
|
|
|
|
isSet = true; |
|
|
|
|
// 32k seems enough for Catch to handle stack overflow,
|
|
|
|
|
// but the value was found experimentally, so there is no strong guarantee
|
|
|
|
|
guaranteeSize = 32 * 1024; |
|
|
|
|
exceptionHandlerHandle = CATCH_NULL; |
|
|
|
|
// Register as first handler in current chain
|
|
|
|
|
exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); |
|
|
|
|
// Pass in guarantee size to be filled
|
|
|
|
|
SetThreadStackGuarantee(&guaranteeSize); |
|
|
|
|
} |
|
|
|
|
class FatalConditionHandler { |
|
|
|
|
bool m_started; |
|
|
|
|
|
|
|
|
|
static void reset() { |
|
|
|
|
if (isSet) { |
|
|
|
|
// Unregister handler and restore the old guarantee
|
|
|
|
|
RemoveVectoredExceptionHandler(exceptionHandlerHandle); |
|
|
|
|
SetThreadStackGuarantee(&guaranteeSize); |
|
|
|
|
exceptionHandlerHandle = CATCH_NULL; |
|
|
|
|
isSet = false; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Install/disengage implementation for specific platform.
|
|
|
|
|
// Should be if-defed to work on current platform, can assume
|
|
|
|
|
// engage-disengage 1:1 pairing.
|
|
|
|
|
|
|
|
|
|
~FatalConditionHandler() { |
|
|
|
|
reset(); |
|
|
|
|
} |
|
|
|
|
private: |
|
|
|
|
static bool isSet; |
|
|
|
|
static ULONG guaranteeSize; |
|
|
|
|
static PVOID exceptionHandlerHandle; |
|
|
|
|
}; |
|
|
|
|
void engage_platform() { |
|
|
|
|
// Register as first handler in current chain
|
|
|
|
|
exceptionHandlerHandle = |
|
|
|
|
AddVectoredExceptionHandler(1, handleVectoredException); |
|
|
|
|
if (!exceptionHandlerHandle) { |
|
|
|
|
throw std::runtime_error("Could not register vectored exception handler"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void disengage_platform() { |
|
|
|
|
if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) { |
|
|
|
|
throw std::runtime_error( |
|
|
|
|
"Could not unregister vectored exception handler"); |
|
|
|
|
} |
|
|
|
|
exceptionHandlerHandle = CATCH_NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool FatalConditionHandler::isSet = false; |
|
|
|
|
ULONG FatalConditionHandler::guaranteeSize = 0; |
|
|
|
|
PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL; |
|
|
|
|
public: |
|
|
|
|
FatalConditionHandler() : m_started(false) { |
|
|
|
|
ULONG guaranteeSize = static_cast<ULONG>(32 * 1024); |
|
|
|
|
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() {} |
|
|
|
|
|
|
|
|
|
void engage() { |
|
|
|
|
assert(!m_started && "Handler cannot be installed twice."); |
|
|
|
|
m_started = true; |
|
|
|
|
engage_platform(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void disengage() { |
|
|
|
|
assert(m_started && |
|
|
|
|
"Handler cannot be uninstalled without being installed first"); |
|
|
|
|
m_started = false; |
|
|
|
|
disengage_platform(); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
} // namespace Catch
|
|
|
|
|
|
|
|
|
|
# endif // CATCH_CONFIG_WINDOWS_SEH
|
|
|
|
|
#endif // CATCH_CONFIG_WINDOWS_SEH
|
|
|
|
|
|
|
|
|
|
#else // Not Windows - assumed to be POSIX compatible //////////////////////////
|
|
|
|
|
|
|
|
|
|
# if !defined(CATCH_CONFIG_POSIX_SIGNALS) |
|
|
|
|
#if !defined(CATCH_CONFIG_POSIX_SIGNALS) |
|
|
|
|
|
|
|
|
|
namespace Catch { |
|
|
|
|
struct FatalConditionHandler { |
|
|
|
|
void reset() {} |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
class FatalConditionHandler { |
|
|
|
|
bool m_started; |
|
|
|
|
|
|
|
|
|
# else // CATCH_CONFIG_POSIX_SIGNALS is defined
|
|
|
|
|
// Install/disengage implementation for specific platform.
|
|
|
|
|
// Should be if-defed to work on current platform, can assume
|
|
|
|
|
// engage-disengage 1:1 pairing.
|
|
|
|
|
void engage_platform() {} |
|
|
|
|
void disengage_platform() {} |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
// Should also have platform-specific implementations as needed
|
|
|
|
|
FatalConditionHandler() : m_started(false) {} |
|
|
|
|
~FatalConditionHandler() {} |
|
|
|
|
|
|
|
|
|
void engage() { |
|
|
|
|
assert(!m_started && "Handler cannot be installed twice."); |
|
|
|
|
m_started = true; |
|
|
|
|
engage_platform(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void disengage() { |
|
|
|
|
assert(m_started && |
|
|
|
|
"Handler cannot be uninstalled without being installed first"); |
|
|
|
|
m_started = false; |
|
|
|
|
disengage_platform(); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
} // namespace Catch
|
|
|
|
|
|
|
|
|
|
#else // CATCH_CONFIG_POSIX_SIGNALS is defined
|
|
|
|
|
|
|
|
|
|
#include <signal.h> |
|
|
|
|
|
|
|
|
|
namespace Catch { |
|
|
|
|
|
|
|
|
|
struct SignalDefs { |
|
|
|
|
int id; |
|
|
|
|
const char* name; |
|
|
|
|
}; |
|
|
|
|
extern SignalDefs signalDefs[]; |
|
|
|
|
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" } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
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 ) { |
|
|
|
|
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 ); |
|
|
|
|
} |
|
|
|
|
struct SignalDefs { |
|
|
|
|
int id; |
|
|
|
|
const char *name; |
|
|
|
|
}; |
|
|
|
|
extern SignalDefs signalDefs[]; |
|
|
|
|
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 = CATCH_NULL; |
|
|
|
|
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], CATCH_NULL); |
|
|
|
|
} |
|
|
|
|
// Return the old stack
|
|
|
|
|
sigaltstack(&oldSigStack, CATCH_NULL); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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 }; |
|
|
|
|
static void handleSignal(int sig) { |
|
|
|
|
char const *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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// 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); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
class FatalConditionHandler { |
|
|
|
|
bool m_started; |
|
|
|
|
|
|
|
|
|
~FatalConditionHandler() { |
|
|
|
|
reset(); |
|
|
|
|
} |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
// Install/disengage implementation for specific platform.
|
|
|
|
|
// Should be if-defed to work on current platform, can assume
|
|
|
|
|
// engage-disengage 1:1 pairing.
|
|
|
|
|
|
|
|
|
|
void engage_platform() { |
|
|
|
|
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]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void disengage_platform() { restorePreviousSignalHandlers(); } |
|
|
|
|
|
|
|
|
|
bool FatalConditionHandler::isSet = false; |
|
|
|
|
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; |
|
|
|
|
stack_t FatalConditionHandler::oldSigStack = {}; |
|
|
|
|
char FatalConditionHandler::altStackMem[SIGSTKSZ] = {}; |
|
|
|
|
public: |
|
|
|
|
FatalConditionHandler() : m_started(false) { |
|
|
|
|
assert(!altStackMem && |
|
|
|
|
"Cannot initialize POSIX signal handler when one already exists"); |
|
|
|
|
if (altStackSize == 0) { |
|
|
|
|
altStackSize = SIGSTKSZ; |
|
|
|
|
} |
|
|
|
|
altStackMem = new char[altStackSize](); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
~FatalConditionHandler() { |
|
|
|
|
delete[] altStackMem; |
|
|
|
|
// We signal that another instance can be constructed by zeroing
|
|
|
|
|
// out the pointer.
|
|
|
|
|
altStackMem = CATCH_NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void engage() { |
|
|
|
|
assert(!m_started && "Handler cannot be installed twice."); |
|
|
|
|
m_started = true; |
|
|
|
|
engage_platform(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void disengage() { |
|
|
|
|
assert(m_started && |
|
|
|
|
"Handler cannot be uninstalled without being installed first"); |
|
|
|
|
m_started = false; |
|
|
|
|
disengage_platform(); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#if defined(__GNUC__) |
|
|
|
|
#pragma GCC diagnostic pop |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
} // namespace Catch
|
|
|
|
|
|
|
|
|
|
# endif // CATCH_CONFIG_POSIX_SIGNALS
|
|
|
|
|
#endif // CATCH_CONFIG_POSIX_SIGNALS
|
|
|
|
|
|
|
|
|
|
#endif // not Windows
|
|
|
|
|
|
|
|
|
|
namespace Catch { |
|
|
|
|
|
|
|
|
|
//! Simple RAII guard for (dis)engaging the FatalConditionHandler
|
|
|
|
|
class FatalConditionHandlerGuard { |
|
|
|
|
FatalConditionHandler *m_handler; |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
FatalConditionHandlerGuard(FatalConditionHandler *handler) |
|
|
|
|
: m_handler(handler) { |
|
|
|
|
m_handler->engage(); |
|
|
|
|
} |
|
|
|
|
~FatalConditionHandlerGuard() { m_handler->disengage(); } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
} // end namespace Catch
|
|
|
|
|
|
|
|
|
|
#include <cassert> |
|
|
|
|
#include <set> |
|
|
|
|
#include <string> |
|
|
|
@ -6938,9 +7075,8 @@ namespace Catch { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void invokeActiveTestCase() { |
|
|
|
|
FatalConditionHandler fatalConditionHandler; // Handle signals
|
|
|
|
|
FatalConditionHandlerGuard _(&m_fatalConditionhandler); |
|
|
|
|
m_activeTestCase->invoke(); |
|
|
|
|
fatalConditionHandler.reset(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
@ -6978,6 +7114,7 @@ namespace Catch { |
|
|
|
|
std::vector<SectionEndInfo> m_unfinishedSections; |
|
|
|
|
std::vector<ITracker*> m_activeSections; |
|
|
|
|
TrackerContext m_trackerContext; |
|
|
|
|
FatalConditionHandler m_fatalConditionhandler; |
|
|
|
|
size_t m_prevPassed; |
|
|
|
|
bool m_shouldReportUnexpected; |
|
|
|
|
}; |
|
|
|
|