From 1f531be3a19055d1402ec6476c5cab80492d3c68 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 30 Jun 2023 10:32:13 -0700 Subject: Make GoogleTest handle SEH exceptions before stack unwinding rather than afterward This ensure the erroring stack frame is visible and accessible when the handler is invoked. Fixes #4298 PiperOrigin-RevId: 544692549 Change-Id: Ia165a8c293e8edc820da5f5ad4416546fffe2493 --- googletest/src/gtest-internal-inl.h | 6 ++-- googletest/src/gtest.cc | 67 +++++++++++++------------------------ 2 files changed, 27 insertions(+), 46 deletions(-) diff --git a/googletest/src/gtest-internal-inl.h b/googletest/src/gtest-internal-inl.h index be82166..1e9b5c2 100644 --- a/googletest/src/gtest-internal-inl.h +++ b/googletest/src/gtest-internal-inl.h @@ -387,10 +387,10 @@ class GTEST_API_ UnitTestOptions { #ifdef GTEST_OS_WINDOWS // Function for supporting the gtest_catch_exception flag. - // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the - // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. + // Returns EXCEPTION_EXECUTE_HANDLER if given SEH exception was handled, or + // EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. - static int GTestShouldProcessSEH(DWORD exception_code); + static int GTestProcessSEH(DWORD seh_code, const char* location); #endif // GTEST_OS_WINDOWS // Returns true if "name" matches the ':' separated list of glob-style diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index 704e1ac..30a5cc3 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -863,13 +863,18 @@ bool UnitTestOptions::FilterMatchesTest(const std::string& test_suite_name, } #if GTEST_HAS_SEH -// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the -// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. -// This function is useful as an __except condition. -int UnitTestOptions::GTestShouldProcessSEH(DWORD seh_code) { +static std::string FormatSehExceptionMessage(DWORD exception_code, + const char* location) { + Message message; + message << "SEH exception with code 0x" << std::setbase(16) << exception_code + << std::setbase(10) << " thrown in " << location << "."; + return message.GetString(); +} + +int UnitTestOptions::GTestProcessSEH(DWORD seh_code, const char* location) { // Google Test should handle a SEH exception if: // 1. the user wants it to, AND - // 2. this is not a breakpoint exception, AND + // 2. this is not a breakpoint exception or stack overflow, AND // 3. this is not a C++ exception (VC++ implements them via SEH, // apparently). // @@ -877,18 +882,20 @@ int UnitTestOptions::GTestShouldProcessSEH(DWORD seh_code) { // (see http://support.microsoft.com/kb/185294 for more information). const DWORD kCxxExceptionCode = 0xe06d7363; - bool should_handle = true; + if (!GTEST_FLAG_GET(catch_exceptions) || seh_code == kCxxExceptionCode || + seh_code == EXCEPTION_BREAKPOINT || + seh_code == EXCEPTION_STACK_OVERFLOW) { + return EXCEPTION_CONTINUE_SEARCH; // Don't handle these exceptions + } - if (!GTEST_FLAG_GET(catch_exceptions)) - should_handle = false; - else if (seh_code == EXCEPTION_BREAKPOINT) - should_handle = false; - else if (seh_code == EXCEPTION_STACK_OVERFLOW) - should_handle = false; - else if (seh_code == kCxxExceptionCode) - should_handle = false; + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatSehExceptionMessage(seh_code, location) + + "\n" + "Stack trace:\n" + + ::testing::internal::GetCurrentOsStackTraceExceptTop(1)); - return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; + return EXCEPTION_EXECUTE_HANDLER; } #endif // GTEST_HAS_SEH @@ -2555,18 +2562,6 @@ bool Test::HasSameFixtureClass() { return true; } -#if GTEST_HAS_SEH - -static std::string FormatSehExceptionMessage(DWORD exception_code, - const char* location) { - Message message; - message << "SEH exception with code 0x" << std::setbase(16) << exception_code - << std::setbase(10) << " thrown in " << location << "."; - return message.GetString(); -} - -#endif // GTEST_HAS_SEH - namespace internal { #if GTEST_HAS_EXCEPTIONS @@ -2608,22 +2603,8 @@ Result HandleSehExceptionsInMethodIfSupported(T* object, Result (T::*method)(), #if GTEST_HAS_SEH __try { return (object->*method)(); - } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT - GetExceptionCode())) { - // We wrap an inner function because VC++ prohibits direct creation of - // objects with destructors on stack in functions using __try - // (see error C2712). - struct Wrapper { - static void ReportFailure(DWORD code, const char* location) { - return internal::ReportFailureInUnknownLocation( - TestPartResult::kFatalFailure, - FormatSehExceptionMessage(code, location) + - "\n" - "Stack trace:\n" + - ::testing::internal::GetCurrentOsStackTraceExceptTop(1)); - } - }; - Wrapper::ReportFailure(GetExceptionCode(), location); + } __except (internal::UnitTestOptions::GTestProcessSEH( // NOLINT + GetExceptionCode(), location)) { return static_cast(0); } #else -- cgit v0.12