googletest
googletest copied to clipboard
Print stacktraces using std::stacktrace if available
Reviewers: See issue #4336 for some design considerations. This PR chooses approach B. The first commit changes the design, and the second commit adds the std::stacktrace feature. If this should be split into two separate pull requests (one commit per PR), let me know.
If std::stacktrace is available (currently only GCC (opt-in feature) and MSVC), use it for printing stack traces.
If both Abseil and std::stacktrace are available, prefer std::stacktrace.
Advantages of std::stacktrace over Abseil:
- Includes file and line information
- Includes DLL information
- Better stack trace quality on Windows
Disadvantages of std::stacktrace compared to Abseil:
- Runs more slowly on Windows
- Includes information which might not be relevant such as byte offsets
- Printed lines are longer thus harder to skim
Before (Windows using Abseil):
[ RUN ] FooTest.Xyz
[snip]\googletest-filter-unittest_.cc(49): error: Failed
Expected failure.
Stack trace:
00007FF69EF90E8D: testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test,void>
00007FF69EF90AC3: testing::internal::HandleExceptionsInMethodIfSupported<testing::Test,void>
00007FF69EF5C01B: testing::Test::Run
00007FF69EF5CCC5: testing::TestInfo::Run
00007FF69EF5D6EC: testing::TestSuite::Run
... Google Test internal frames ...
[ FAILED ] FooTest.Xyz (21 ms)
After (Windows using MSVC STL's std::stacktrace):
[ RUN ] FooTest.Xyz
[snip]\googletest-filter-unittest_.cc(49): error: Failed
Expected failure.
Stack trace:
00007FF6770283A9: googletest_filter_unittest_!`anonymous namespace'::FooTest_Xyz_Test::TestBody+0x89 [snip]\googletest-filter-unittest_.cc:49
00007FF677080E8D: googletest_filter_unittest_!testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test,void>+0x1D [snip]\gtest.cc:2609
00007FF677080AC3: googletest_filter_unittest_!testing::internal::HandleExceptionsInMethodIfSupported<testing::Test,void>+0x73 [snip]\gtest.cc:2652
00007FF67704C01B: googletest_filter_unittest_!testing::Test::Run+0xAB [snip]\gtest.cc:2698
... Google Test internal frames ...
[ FAILED ] FooTest.Xyz (127 ms)
Recently, we found a problem that: after gtest started taking dependency on abseil, the "::testing::InitGoogleTest" function will call SymInitialize Windows API indirectly. However, the API can only be called once per process. For example,
#include <iostream>
#include <Windows.h>
#include <DbgHelp.h>
int main()
{
HANDLE process = GetCurrentProcess();
SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
if (!SymInitialize(process, nullptr, true)) {
return -1;
}
if (!SymInitialize(process, nullptr, true)) {
return -1;
}
return 0;
}
The second SymInitialize call would definitely fail. So, if the library we are testing also has its own backtrace implementation, the extra "SymInitialize" function call would cause trouble. I wonder how it is handled in VC++ runtime's "<stacktrace>" library.
I think std::stacktrace has two benefits compared to the existing one:
- You don't need to worry about initialization/cleanup. The C++ runtime should handle it.
- It dynamically loads dbghelp.dll. So the dependency is optional.
@derekmauro any plans to merge this?
Recently, we found a problem that: after gtest started taking dependency on abseil, the "::testing::InitGoogleTest" function will call SymInitialize Windows API indirectly. However, the API can only be called once per process. For example,
#include <iostream> #include <Windows.h> #include <DbgHelp.h> int main() { HANDLE process = GetCurrentProcess(); SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME); if (!SymInitialize(process, nullptr, true)) { return -1; } if (!SymInitialize(process, nullptr, true)) { return -1; } return 0; }
The second SymInitialize call would definitely fail. So, if the library we are testing also has its own backtrace implementation, the extra "SymInitialize" function call would cause trouble. I wonder how it is handled in VC++ runtime's "
" library.
Is this getting some attention? All that is need to be done is not to use GetCurrentProcess()