Backport
https://github.com/catchorg/Catch2/commit/6c6cfe126aa5f4a0cfbe8e805db550e47e26aab1
And run:
python2 scripts/generateSingleHeader.py
Index: leatherman-1.12.4/catch/inc/catch.hpp
===================================================================
--- leatherman-1.12.4.orig/catch/inc/catch.hpp
+++ leatherman-1.12.4/catch/inc/catch.hpp
@@ -1,6 +1,6 @@
 /*
  *  Catch v1.10.0
- *  Generated: 2017-08-26 15:16:46.676990
+ *  Generated: 2022-10-12 22:42:54.972394
  *  ----------------------------------------------------------
  *  This file has been merged from multiple headers. Please don't edit it directly
  *  Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
@@ -6320,9 +6320,12 @@ 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
+    //! Signals fatal error message to the run context
     inline void reportFatal( std::string const& message ) {
         IContext& context = Catch::getCurrentContext();
         IResultCapture* resultCapture = context.getResultCapture();
@@ -6360,8 +6363,31 @@ namespace Catch {
 #  if !defined ( CATCH_CONFIG_WINDOWS_SEH )
 
 namespace Catch {
-    struct FatalConditionHandler {
-        void reset() {}
+    class FatalConditionHandler {
+        bool m_started = 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() {}
+        void disengage_platform() {}
+
+    public:
+        // Should also have platform-specific implementations as needed
+        FatalConditionHandler() {}
+        ~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();
+        }
     };
 }
 
@@ -6381,53 +6407,72 @@ namespace Catch {
         { 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);
-                }
+    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;
         }
+        // If its not an exception we care about, pass it along.
+        // This stops us from eating debugger breaks etc.
+        return EXCEPTION_CONTINUE_SEARCH;
+    }
 
-        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;
+    // 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;
+
+    class FatalConditionHandler {
+        bool m_started = 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() {
             // Register as first handler in current chain
             exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
-            // Pass in guarantee size to be filled
-            SetThreadStackGuarantee(&guaranteeSize);
+            if (!exceptionHandlerHandle) {
+                throw std::runtime_error("Could not register vectored exception handler");
+            }
         }
 
-        static void reset() {
-            if (isSet) {
-                // Unregister handler and restore the old guarantee
-                RemoveVectoredExceptionHandler(exceptionHandlerHandle);
-                SetThreadStackGuarantee(&guaranteeSize);
-                exceptionHandlerHandle = CATCH_NULL;
-                isSet = false;
+        void disengage_platform() {
+            if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) {
+                throw std::runtime_error("Could not unregister vectored exception handler");
             }
+            exceptionHandlerHandle = CATCH_NULL;
         }
 
-        ~FatalConditionHandler() {
-            reset();
+    public:
+        FatalConditionHandler() {
+            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.";
+            }
         }
-    private:
-        static bool isSet;
-        static ULONG guaranteeSize;
-        static PVOID exceptionHandlerHandle;
-    };
 
-    bool FatalConditionHandler::isSet = false;
-    ULONG FatalConditionHandler::guaranteeSize = 0;
-    PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL;
+        // 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
 
@@ -6438,8 +6483,31 @@ namespace Catch {
 #  if !defined(CATCH_CONFIG_POSIX_SIGNALS)
 
 namespace Catch {
-    struct FatalConditionHandler {
-        void reset() {}
+    class FatalConditionHandler {
+        bool m_started = 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() {}
+        void disengage_platform() {}
+
+    public:
+        // Should also have platform-specific implementations as needed
+        FatalConditionHandler() {}
+        ~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();
+        }
     };
 }
 
@@ -6463,29 +6531,56 @@ namespace Catch {
             { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
     };
 
-    struct FatalConditionHandler {
+// 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 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;
-                }
+    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);
+    }
+
+    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;
             }
-            reset();
-            reportFatal(name);
-            raise( sig );
         }
+        // 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() {
-            isSet = true;
+    class FatalConditionHandler {
+        bool m_started = 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;
@@ -6500,26 +6595,42 @@ namespace Catch {
             }
         }
 
-        ~FatalConditionHandler() {
-            reset();
+        void disengage_platform() {
+            restorePreviousSignalHandlers();
         }
-        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;
+
+    public:
+        FatalConditionHandler() {
+            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();
         }
     };
 
-    bool FatalConditionHandler::isSet = false;
-    struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
-    stack_t FatalConditionHandler::oldSigStack = {};
-    char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
+#if defined(__GNUC__)
+#    pragma GCC diagnostic pop
+#endif
 
 } // namespace Catch
 
@@ -6527,6 +6638,23 @@ namespace Catch {
 
 #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 <set>
 #include <string>
 
@@ -6865,9 +6993,8 @@ namespace Catch {
         }
 
         void invokeActiveTestCase() {
-            FatalConditionHandler fatalConditionHandler; // Handle signals
+            FatalConditionHandlerGuard _(&m_fatalConditionhandler);
             m_activeTestCase->invoke();
-            fatalConditionHandler.reset();
         }
 
     private:
@@ -6905,6 +7032,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;
     };
Index: leatherman-1.12.4/catch/CMakeLists.txt
===================================================================
--- leatherman-1.12.4.orig/catch/CMakeLists.txt
+++ leatherman-1.12.4/catch/CMakeLists.txt
@@ -1 +1 @@
-add_leatherman_vendored("Catch-1.10.0.zip" "Catch-1.10.0" "single_include")
+add_leatherman_includes("catch/include")
