Fix disengage failure logs for FatalConditionHandlerGuard

FatalConditionHandlerGuard is used within RunContext::invokeActiveTestCase().
The intent of this guard is to avoid binary crash without failed test being
reported.
Still in case FatalConditionHandlerGuard destructor being called during stack
unwinding AND finds unexpected top-level filter for SEH unhandled exception,
the binary may still crash. As result of such crash the original exception
details are being hidden.

As the Catch2 provides only `CATCH_CATCH_ANON` macro, with no access to
exception details by design, looks like the best way to handle issue is to:
 - state requirements explicitly by `noexcept` specifier
 - use `Catch::cerr()` to print out possible issue notification

Signed-off-by: Kochetkov, Yuriy <yuriyx.kochetkov@intel.com>
This commit is contained in:
Kochetkov, Yuriy 2022-02-08 13:43:40 +03:00 committed by Martin Hořeňovský
parent 7882f7359e
commit 2ce64d1d8f
2 changed files with 9 additions and 7 deletions

View File

@ -40,7 +40,7 @@ namespace Catch {
// If neither SEH nor signal handling is required, the handler impls // If neither SEH nor signal handling is required, the handler impls
// do not have to do anything, and can be empty. // do not have to do anything, and can be empty.
void FatalConditionHandler::engage_platform() {} void FatalConditionHandler::engage_platform() {}
void FatalConditionHandler::disengage_platform() {} void FatalConditionHandler::disengage_platform() noexcept {}
FatalConditionHandler::FatalConditionHandler() = default; FatalConditionHandler::FatalConditionHandler() = default;
FatalConditionHandler::~FatalConditionHandler() = default; FatalConditionHandler::~FatalConditionHandler() = default;
@ -124,9 +124,11 @@ namespace Catch {
previousTopLevelExceptionFilter = SetUnhandledExceptionFilter(topLevelExceptionFilter); previousTopLevelExceptionFilter = SetUnhandledExceptionFilter(topLevelExceptionFilter);
} }
void FatalConditionHandler::disengage_platform() { void FatalConditionHandler::disengage_platform() noexcept {
if (SetUnhandledExceptionFilter(previousTopLevelExceptionFilter) != topLevelExceptionFilter) { if (SetUnhandledExceptionFilter(previousTopLevelExceptionFilter) != topLevelExceptionFilter) {
CATCH_RUNTIME_ERROR("Could not restore previous top level exception filter"); Catch::cerr()
<< "Unexpected SEH unhandled exception filter on disengage."
<< " The filter was restored, but might be rolled back unexpectedly.";
} }
previousTopLevelExceptionFilter = nullptr; previousTopLevelExceptionFilter = nullptr;
} }
@ -168,7 +170,7 @@ namespace Catch {
static stack_t oldSigStack{}; static stack_t oldSigStack{};
static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{}; static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
static void restorePreviousSignalHandlers() { static void restorePreviousSignalHandlers() noexcept {
// We set signal handlers back to the previous ones. Hopefully // We set signal handlers back to the previous ones. Hopefully
// nobody overwrote them in the meantime, and doesn't expect // nobody overwrote them in the meantime, and doesn't expect
// their signal handlers to live past ours given that they // their signal handlers to live past ours given that they
@ -231,7 +233,7 @@ namespace Catch {
#endif #endif
void FatalConditionHandler::disengage_platform() { void FatalConditionHandler::disengage_platform() noexcept {
restorePreviousSignalHandlers(); restorePreviousSignalHandlers();
} }

View File

@ -32,7 +32,7 @@ namespace Catch {
// Should be if-defed to work on current platform, can assume // Should be if-defed to work on current platform, can assume
// engage-disengage 1:1 pairing. // engage-disengage 1:1 pairing.
void engage_platform(); void engage_platform();
void disengage_platform(); void disengage_platform() noexcept;
public: public:
// Should also have platform-specific implementations as needed // Should also have platform-specific implementations as needed
FatalConditionHandler(); FatalConditionHandler();
@ -44,7 +44,7 @@ namespace Catch {
engage_platform(); engage_platform();
} }
void disengage() { void disengage() noexcept {
assert(m_started && "Handler cannot be uninstalled without being installed first"); assert(m_started && "Handler cannot be uninstalled without being installed first");
m_started = false; m_started = false;
disengage_platform(); disengage_platform();