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
This commit is contained in:
		
				
					committed by
					
						
						Copybara-Service
					
				
			
			
				
	
			
			
			
						parent
						
							251e720391
						
					
				
				
					commit
					1f531be3a1
				
			@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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<Result>(0);
 | 
			
		||||
  }
 | 
			
		||||
#else
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user