Skip to content

Commit 0e0bb74

Browse files
committed
Pull in code from Catch v2.13.8 to handle MINSIGSTKSZ not being constexpr.
1 parent a47fcdd commit 0e0bb74

1 file changed

Lines changed: 120 additions & 121 deletions

File tree

tests/include/catch.hpp

Lines changed: 120 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
#define CATCH_VERSION_MAJOR 2
1717
#define CATCH_VERSION_MINOR 13
1818
#define CATCH_VERSION_PATCH 4
19+
20+
/*
21+
Note: includes changes from patch 8 needed for when MINSIGSTKSZ is no longer a
22+
constexpr.
23+
*/
1924

2025
#ifdef __clang__
2126
# pragma clang system_header
@@ -67,12 +72,12 @@
6772
// start catch_platform.h
6873

6974
#ifdef __APPLE__
70-
# include <TargetConditionals.h>
75+
# include <TargetConditionals.h>
7176
# if TARGET_OS_OSX == 1
72-
# define CATCH_PLATFORM_MAC
77+
# define CATCH_PLATFORM_MAC
7378
# elif TARGET_OS_IPHONE == 1
74-
# define CATCH_PLATFORM_IPHONE
75-
# endif
79+
# define CATCH_PLATFORM_IPHONE
80+
# endif
7681

7782
#elif defined(linux) || defined(__linux) || defined(__linux__)
7883
# define CATCH_PLATFORM_LINUX
@@ -6339,8 +6344,8 @@ namespace Catch {
63396344

63406345
void writeTestCase(TestCaseNode const& testCaseNode);
63416346

6342-
void writeSection(std::string const& className,
6343-
std::string const& rootName,
6347+
void writeSection( std::string const& className,
6348+
std::string const& rootName,
63446349
SectionNode const& sectionNode);
63456350

63466351
void writeAssertions(SectionNode const& sectionNode);
@@ -7980,86 +7985,58 @@ namespace Catch {
79807985

79817986
// start catch_fatal_condition.h
79827987

7983-
// start catch_windows_h_proxy.h
7984-
7985-
7986-
#if defined(CATCH_PLATFORM_WINDOWS)
7987-
7988-
#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
7989-
# define CATCH_DEFINED_NOMINMAX
7990-
# define NOMINMAX
7991-
#endif
7992-
#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
7993-
# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
7994-
# define WIN32_LEAN_AND_MEAN
7995-
#endif
7996-
7997-
#ifdef __AFXDLL
7998-
#include <AfxWin.h>
7999-
#else
8000-
#include <windows.h>
8001-
#endif
8002-
8003-
#ifdef CATCH_DEFINED_NOMINMAX
8004-
# undef NOMINMAX
8005-
#endif
8006-
#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
8007-
# undef WIN32_LEAN_AND_MEAN
8008-
#endif
8009-
8010-
#endif // defined(CATCH_PLATFORM_WINDOWS)
8011-
8012-
// end catch_windows_h_proxy.h
8013-
#if defined( CATCH_CONFIG_WINDOWS_SEH )
7988+
#include <cassert>
80147989

80157990
namespace Catch {
80167991

8017-
struct FatalConditionHandler {
8018-
8019-
static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo);
7992+
// Wrapper for platform-specific fatal error (signals/SEH) handlers
7993+
//
7994+
// Tries to be cooperative with other handlers, and not step over
7995+
// other handlers. This means that unknown structured exceptions
7996+
// are passed on, previous signal handlers are called, and so on.
7997+
//
7998+
// Can only be instantiated once, and assumes that once a signal
7999+
// is caught, the binary will end up terminating. Thus, there
8000+
class FatalConditionHandler {
8001+
bool m_started = false;
8002+
8003+
// Install/disengage implementation for specific platform.
8004+
// Should be if-defed to work on current platform, can assume
8005+
// engage-disengage 1:1 pairing.
8006+
void engage_platform();
8007+
void disengage_platform();
8008+
public:
8009+
// Should also have platform-specific implementations as needed
80208010
FatalConditionHandler();
8021-
static void reset();
80228011
~FatalConditionHandler();
80238012

8024-
private:
8025-
static bool isSet;
8026-
static ULONG guaranteeSize;
8027-
static PVOID exceptionHandlerHandle;
8028-
};
8029-
8030-
} // namespace Catch
8031-
8032-
#elif defined ( CATCH_CONFIG_POSIX_SIGNALS )
8033-
8034-
#include <signal.h>
8035-
8036-
namespace Catch {
8037-
8038-
struct FatalConditionHandler {
8039-
8040-
static bool isSet;
8041-
static struct sigaction oldSigActions[];
8042-
static stack_t oldSigStack;
8043-
static char altStackMem[];
8044-
8045-
static void handleSignal( int sig );
8013+
void engage() {
8014+
assert(!m_started && "Handler cannot be installed twice.");
8015+
m_started = true;
8016+
engage_platform();
8017+
}
80468018

8047-
FatalConditionHandler();
8048-
~FatalConditionHandler();
8049-
static void reset();
8019+
void disengage() {
8020+
assert(m_started && "Handler cannot be uninstalled without being installed first");
8021+
m_started = false;
8022+
disengage_platform();
8023+
}
80508024
};
80518025

8052-
} // namespace Catch
8053-
8054-
#else
8055-
8056-
namespace Catch {
8057-
struct FatalConditionHandler {
8058-
void reset();
8026+
//! Simple RAII guard for (dis)engaging the FatalConditionHandler
8027+
class FatalConditionHandlerGuard {
8028+
FatalConditionHandler* m_handler;
8029+
public:
8030+
FatalConditionHandlerGuard(FatalConditionHandler* handler):
8031+
m_handler(handler) {
8032+
m_handler->engage();
8033+
}
8034+
~FatalConditionHandlerGuard() {
8035+
m_handler->disengage();
8036+
}
80598037
};
8060-
}
80618038

8062-
#endif
8039+
} // end namespace Catch
80638040

80648041
// end catch_fatal_condition.h
80658042
#include <string>
@@ -10743,13 +10720,18 @@ namespace Catch {
1074310720
#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
1074410721

1074510722
namespace {
10746-
// Report the error condition
10723+
//! Signals fatal error message to the run context
1074710724
void reportFatal( char const * const message ) {
1074810725
Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
1074910726
}
10750-
}
1075110727

10752-
#endif // signals/SEH handling
10728+
//! Minimal size Catch2 needs for its own fatal error handling.
10729+
//! Picked anecdotally, so it might not be sufficient on all
10730+
//! platforms, and for all configurations.
10731+
constexpr std::size_t minStackSizeForErrors = 32 * 1024;
10732+
} // end unnamed namespace
10733+
10734+
#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS
1075310735

1075410736
#if defined( CATCH_CONFIG_WINDOWS_SEH )
1075510737

@@ -10793,7 +10775,7 @@ namespace Catch {
1079310775
if (isSet) {
1079410776
RemoveVectoredExceptionHandler(exceptionHandlerHandle);
1079510777
SetThreadStackGuarantee(&guaranteeSize);
10796-
exceptionHandlerHandle = nullptr;
10778+
exceptionHandlerHandle = nullptr;
1079710779
isSet = false;
1079810780
}
1079910781
}
@@ -10810,17 +10792,15 @@ PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
1081010792

1081110793
#elif defined( CATCH_CONFIG_POSIX_SIGNALS )
1081210794

10795+
#include <signal.h>
10796+
1081310797
namespace Catch {
1081410798

1081510799
struct SignalDefs {
1081610800
int id;
1081710801
const char* name;
1081810802
};
1081910803

10820-
// 32kb for the alternate stack seems to be sufficient. However, this value
10821-
// is experimentally determined, so that's not guaranteed.
10822-
static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
10823-
1082410804
static SignalDefs signalDefs[] = {
1082510805
{ SIGINT, "SIGINT - Terminal interrupt signal" },
1082610806
{ SIGILL, "SIGILL - Illegal instruction signal" },
@@ -10830,24 +10810,66 @@ namespace Catch {
1083010810
{ SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
1083110811
};
1083210812

10833-
void FatalConditionHandler::handleSignal( int sig ) {
10813+
// Older GCCs trigger -Wmissing-field-initializers for T foo = {}
10814+
// which is zero initialization, but not explicit. We want to avoid
10815+
// that.
10816+
#if defined(__GNUC__)
10817+
# pragma GCC diagnostic push
10818+
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
10819+
#endif
10820+
10821+
static char* altStackMem = nullptr;
10822+
static std::size_t altStackSize = 0;
10823+
static stack_t oldSigStack{};
10824+
static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
10825+
10826+
static void restorePreviousSignalHandlers() {
10827+
// We set signal handlers back to the previous ones. Hopefully
10828+
// nobody overwrote them in the meantime, and doesn't expect
10829+
// their signal handlers to live past ours given that they
10830+
// installed them after ours..
10831+
for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
10832+
sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
10833+
}
10834+
// Return the old stack
10835+
sigaltstack(&oldSigStack, nullptr);
10836+
}
10837+
10838+
static void handleSignal( int sig ) {
1083410839
char const * name = "<unknown signal>";
1083510840
for (auto const& def : signalDefs) {
1083610841
if (sig == def.id) {
1083710842
name = def.name;
1083810843
break;
1083910844
}
1084010845
}
10841-
reset();
10842-
reportFatal(name);
10846+
// We need to restore previous signal handlers and let them do
10847+
// their thing, so that the users can have the debugger break
10848+
// when a signal is raised, and so on.
10849+
restorePreviousSignalHandlers();
10850+
reportFatal( name );
1084310851
raise( sig );
1084410852
}
1084510853

1084610854
FatalConditionHandler::FatalConditionHandler() {
10847-
isSet = true;
10855+
assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists");
10856+
if (altStackSize == 0) {
10857+
altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);
10858+
}
10859+
altStackMem = new char[altStackSize]();
10860+
}
10861+
10862+
FatalConditionHandler::~FatalConditionHandler() {
10863+
delete[] altStackMem;
10864+
// We signal that another instance can be constructed by zeroing
10865+
// out the pointer.
10866+
altStackMem = nullptr;
10867+
}
10868+
10869+
void FatalConditionHandler::engage_platform() {
1084810870
stack_t sigStack;
1084910871
sigStack.ss_sp = altStackMem;
10850-
sigStack.ss_size = sigStackSize;
10872+
sigStack.ss_size = altStackSize;
1085110873
sigStack.ss_flags = 0;
1085210874
sigaltstack(&sigStack, &oldSigStack);
1085310875
struct sigaction sa = { };
@@ -10859,40 +10881,17 @@ namespace Catch {
1085910881
}
1086010882
}
1086110883

10862-
FatalConditionHandler::~FatalConditionHandler() {
10863-
reset();
10864-
}
10884+
#if defined(__GNUC__)
10885+
# pragma GCC diagnostic pop
10886+
#endif
1086510887

10866-
void FatalConditionHandler::reset() {
10867-
if( isSet ) {
10868-
// Set signals back to previous values -- hopefully nobody overwrote them in the meantime
10869-
for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
10870-
sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
10871-
}
10872-
// Return the old stack
10873-
sigaltstack(&oldSigStack, nullptr);
10874-
isSet = false;
10875-
}
10888+
void FatalConditionHandler::disengage_platform() {
10889+
restorePreviousSignalHandlers();
1087610890
}
1087710891

10878-
bool FatalConditionHandler::isSet = false;
10879-
struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
10880-
stack_t FatalConditionHandler::oldSigStack = {};
10881-
char FatalConditionHandler::altStackMem[sigStackSize] = {};
10882-
10883-
} // namespace Catch
10884-
10885-
#else
10886-
10887-
namespace Catch {
10888-
void FatalConditionHandler::reset() {}
10889-
}
10890-
10891-
#endif // signals/SEH handling
10892+
} // end namespace Catch
1089210893

10893-
#if defined(__GNUC__)
10894-
# pragma GCC diagnostic pop
10895-
#endif
10894+
#endif // CATCH_CONFIG_POSIX_SIGNALS
1089610895
// end catch_fatal_condition.cpp
1089710896
// start catch_generators.cpp
1089810897

@@ -12957,7 +12956,7 @@ namespace Catch {
1295712956
void RunContext::invokeActiveTestCase() {
1295812957
FatalConditionHandler fatalConditionHandler; // Handle signals
1295912958
m_activeTestCase->invoke();
12960-
fatalConditionHandler.reset();
12959+
restorePreviousSignalHandlers();
1296112960
}
1296212961

1296312962
void RunContext::handleUnfinishedSections() {
@@ -16888,8 +16887,8 @@ namespace Catch {
1688816887
writeSection( className, "", rootSection );
1688916888
}
1689016889

16891-
void JunitReporter::writeSection( std::string const& className,
16892-
std::string const& rootName,
16890+
void JunitReporter::writeSection( std::string const& className,
16891+
std::string const& rootName,
1689316892
SectionNode const& sectionNode ) {
1689416893
std::string name = trim( sectionNode.stats.sectionInfo.name );
1689516894
if( !rootName.empty() )

0 commit comments

Comments
 (0)