Skip to content

Commit

Permalink
Print stack traces on SEH exceptions on Windows
Browse files Browse the repository at this point in the history
Also tidies up a couple of things:
- Prevent handling of stack overflows, which cannot be done safely
- `exception_code` is a macro, so we rename it
- The `std::string` heap allocation was unnecessary

Fixes #4298

PiperOrigin-RevId: 544117790
Change-Id: I8ba61f87119d5fbdb1f653700d9867ca6f8c28ce
  • Loading branch information
Abseil Team authored and copybara-github committed Jun 28, 2023
1 parent 2acd538 commit 687c589
Showing 1 changed file with 21 additions and 18 deletions.
39 changes: 21 additions & 18 deletions googletest/src/gtest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,7 @@ bool UnitTestOptions::FilterMatchesTest(const std::string& test_suite_name,
// 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 exception_code) {
int UnitTestOptions::GTestShouldProcessSEH(DWORD seh_code) {
// Google Test should handle a SEH exception if:
// 1. the user wants it to, AND
// 2. this is not a breakpoint exception, AND
Expand All @@ -881,9 +881,11 @@ int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) {

if (!GTEST_FLAG_GET(catch_exceptions))
should_handle = false;
else if (exception_code == EXCEPTION_BREAKPOINT)
else if (seh_code == EXCEPTION_BREAKPOINT)
should_handle = false;
else if (exception_code == kCxxExceptionCode)
else if (seh_code == EXCEPTION_STACK_OVERFLOW)
should_handle = false;
else if (seh_code == kCxxExceptionCode)
should_handle = false;

return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
Expand Down Expand Up @@ -2555,17 +2557,12 @@ bool Test::HasSameFixtureClass() {

#if GTEST_HAS_SEH

// Adds an "exception thrown" fatal failure to the current test. This
// function returns its result via an output parameter pointer because VC++
// prohibits creation of objects with destructors on stack in functions
// using __try (see error C2712).
static std::string* FormatSehExceptionMessage(DWORD exception_code,
const char* location) {
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 new std::string(message.GetString());
return message.GetString();
}

#endif // GTEST_HAS_SEH
Expand Down Expand Up @@ -2613,14 +2610,20 @@ Result HandleSehExceptionsInMethodIfSupported(T* object, Result (T::*method)(),
return (object->*method)();
} __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT
GetExceptionCode())) {
// We create the exception message on the heap because VC++ prohibits
// creation of objects with destructors on stack in functions using __try
// We wrap an inner function because VC++ prohibits direct creation of
// objects with destructors on stack in functions using __try
// (see error C2712).
std::string* exception_message =
FormatSehExceptionMessage(GetExceptionCode(), location);
internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,
*exception_message);
delete exception_message;
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);
return static_cast<Result>(0);
}
#else
Expand Down

0 comments on commit 687c589

Please sign in to comment.