1
0
mirror of https://github.com/catchorg/Catch2.git synced 2025-04-28 19:53:52 +00:00
Catch2/src/catch2/internal/catch_fatal_condition_handler.hpp
Martin Hořeňovský c0d0a50bdb
Significantly refactor fatal error handling
Because new glibc has changed `MINSIGSTKSZ` to be a syscall instead
of being constant, the signal posix handling needed changes, as it
used the value in constexpr context, for deciding size of an array.
It would be simple to fix it by having the handler determine the
signal handling stack size and allocate the memory every time the
handler is being installed, but that would add another allocation
and a syscall every time a test case is entered.

Instead, I split apart the idea of preparing fatal error handlers,
and engaging them, so that the memory can be allocated only once
and still be guarded by RAII.

Also turns out that Catch2's use of `MINSIGSTKSZ` was wrong, and
we should've been using `SIGSTKSZ` the whole time, which we use now.

Closes #2178
2021-05-09 23:34:15 +02:00

70 lines
2.2 KiB
C++

// Copyright Catch2 Authors
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
#ifndef CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED
#define CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED
#include <catch2/internal/catch_platform.hpp>
#include <catch2/internal/catch_compiler_capabilities.hpp>
#include <cassert>
namespace Catch {
/**
* Wrapper for platform-specific fatal error (signals/SEH) handlers
*
* Tries to be cooperative with other handlers, and not step over
* other handlers. This means that unknown structured exceptions
* are passed on, previous signal handlers are called, and so on.
*
* Can only be instantiated once, and assumes that once a signal
* is caught, the binary will end up terminating. Thus, there
*/
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();
}
};
//! 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
#endif // CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED