From 2552ed064fc91c15b354595505c59e8d871ba427 Mon Sep 17 00:00:00 2001 From: Scott Hutchinson Date: Fri, 25 Nov 2022 13:44:01 -0800 Subject: [PATCH] Fix issue with Address Sanitizer on Windows. --- include/internal/catch_fatal_condition.cpp | 17 +++++------ projects/SelfTest/UsageTests/Misc.tests.cpp | 32 +++++++++++++++++++++ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/include/internal/catch_fatal_condition.cpp b/include/internal/catch_fatal_condition.cpp index 873e2ed5..3337a98d 100644 --- a/include/internal/catch_fatal_condition.cpp +++ b/include/internal/catch_fatal_condition.cpp @@ -85,7 +85,7 @@ namespace Catch { { static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" }, }; - static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + static LONG CALLBACK topLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) { for (auto const& def : signalDefs) { if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { reportFatal(def.name); @@ -99,7 +99,7 @@ namespace Catch { // 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 = nullptr; + static LPTOP_LEVEL_EXCEPTION_FILTER previousTopLevelExceptionFilter = nullptr; // For MSVC, we reserve part of the stack memory for handling @@ -121,18 +121,15 @@ namespace Catch { void FatalConditionHandler::engage_platform() { - // Register as first handler in current chain - exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); - if (!exceptionHandlerHandle) { - CATCH_RUNTIME_ERROR("Could not register vectored exception handler"); - } + // Register as a the top level exception filter. + previousTopLevelExceptionFilter = SetUnhandledExceptionFilter(topLevelExceptionFilter); } void FatalConditionHandler::disengage_platform() { - if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) { - CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler"); + if (SetUnhandledExceptionFilter(reinterpret_cast(previousTopLevelExceptionFilter)) != topLevelExceptionFilter) { + CATCH_RUNTIME_ERROR("Could not restore previous top level exception filter"); } - exceptionHandlerHandle = nullptr; + previousTopLevelExceptionFilter = nullptr; } } // end namespace Catch diff --git a/projects/SelfTest/UsageTests/Misc.tests.cpp b/projects/SelfTest/UsageTests/Misc.tests.cpp index dcd9fc8a..bfd217fe 100644 --- a/projects/SelfTest/UsageTests/Misc.tests.cpp +++ b/projects/SelfTest/UsageTests/Misc.tests.cpp @@ -7,6 +7,7 @@ */ #include "catch.hpp" +#include #ifdef __clang__ # pragma clang diagnostic ignored "-Wc++98-compat" @@ -491,3 +492,34 @@ TEMPLATE_TEST_CASE_SIG("#1954 - 7 arg template test case sig compiles", "[regres } }} // namespace MiscTests + +#if defined(CATCH_PLATFORM_WINDOWS) +void throw_and_catch() +{ + __try { + RaiseException(0xC0000005, 0, 0, NULL); + } + __except (1) + { + + } +} + + +TEST_CASE("Validate SEH behavior - handled", "[approvals][FatalConditionHandler][CATCH_PLATFORM_WINDOWS]") +{ + // Validate that Catch2 framework correctly handles tests raising and handling SEH exceptions. + throw_and_catch(); +} + +void throw_no_catch() +{ + RaiseException(0xC0000005, 0, 0, NULL); +} + +TEST_CASE("Validate SEH behavior - unhandled", "[.approvals][FatalConditionHandler][CATCH_PLATFORM_WINDOWS]") +{ + // Validate that Catch2 framework correctly handles tests raising and not handling SEH exceptions. + throw_no_catch(); +} +#endif