You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
With shouldRedirectStdOut enabled, Windows can hang on writing to std::cerr
Expected behavior
No hangs should happen
Reproduction steps
Steps to reproduce the bug.
This is a really obnoxious one to track down but I was able to create a reproduction that reproduces it....sometimes (catch_repro.zip). You can run CMake on it to generate a visual studio project and then run the resulting exe with the -r quiet argument. You'll know if it hits the actual issue if the program is hung and attaching a debugger reveals that it is blocked with the following stack trace (I had better luck today running from the command prompt and then using visual studio to attach a debugger once I saw it hanging):
ucrtbased.dll!_lock_file(_iobuf * stream) Line 141 C++
msvcp140d.dll!std::basic_filebuf<char,std::char_traits<char>>::_Lock() Line 376 C++
catch_repro.exe!std::basic_ostream<char,std::char_traits<char>>::_Sentry_base::_Sentry_base(std::basic_ostream<char,std::char_traits<char>> & _Ostr) Line 78 C++
catch_repro.exe!std::basic_ostream<char,std::char_traits<char>>::sentry::sentry(std::basic_ostream<char,std::char_traits<char>> & _Ostr) Line 96 C++
catch_repro.exe!std::_Insert_string<char,std::char_traits<char>,unsigned __int64>(std::basic_ostream<char,std::char_traits<char>> & _Ostr, const char * const _Data, const unsigned __int64 _Size) Line 480 C++
catch_repro.exe!std::operator<<<char,std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> & _Ostr, const std::basic_string_view<char,std::char_traits<char>> _Str) Line 1782 C++
catch_repro.exe!fleece_Catch::CaseListReporter::sectionStarting(const Catch::SectionInfo & _sectionInfo) Line 466 C++
catch_repro.exe!Catch::RunContext::sectionStarted(Catch::StringRef sectionName, const Catch::SourceLineInfo & sectionLineInfo, Catch::Counts & assertions) Line 5917 C++
catch_repro.exe!Catch::Section::Section(Catch::SectionInfo && info) Line 6316 C++
catch_repro.exe!Catch::NWayMethodTestInvoker<`anonymous namespace'::CATCH2_INTERNAL_TEST_2>::invoke() Line 18 C++
catch_repro.exe!Catch::TestCaseHandle::invoke() Line 7163 C++
catch_repro.exe!Catch::RunContext::invokeActiveTestCase() Line 6161 C++
catch_repro.exe!Catch::RunContext::runCurrentTest() Line 6124 C++
catch_repro.exe!Catch::RunContext::runTest(const Catch::TestCaseHandle & testCase) Line 5822 C++
catch_repro.exe!Catch::`anonymous namespace'::TestGroup::execute() Line 1253 C++
catch_repro.exe!Catch::Session::runInternal() Line 1473 C++
catch_repro.exe!Catch::Session::run() Line 1405 C++
catch_repro.exe!Catch::Session::run<char>(int argc, const char * const * argv) Line 4937 C++
Platform information:
OS: Windows 10.0.10945 Pro
Compiler+version: MSVC 19.41.34120.0
Catch version: v3.7.1
Additional context
The underlying issue here, in my opinion, is a weird decision by the Microsoft C++ runtime. Whenever you write to some sort of stream, the underlying rdbuf is locked and then unlocked when the write is done. Seems sane enough except that the way it does it is by asking the stream for its rdbuf in the constructor, locking it, and then asking the stream for its rdbuf again in the destructor and unlocking that. My theory is that since Catch is so wildly swapping the rdbuf back and forth, it might be switching the rdbuf between the constructor and destructor while another thread is writing and thus causing the original rdbuf to be locked forever. I experimented by having catch do the same locking when swapping the rdbuf but that did not solve the issue. In fact the only thing that DOES work is commenting out the stopRedirect logic so that only startRedirect actually does anything. Everything I want to be logged is still logged due to Catch using Catch::cout() instead of std::cout to log so I am willing to patch it that way, but this problem is bothering me quite a bit.
Sorry this isn't quite a minimal project as it uses a custom reporter (slightly altered console reporter) and a custom invoker to allow variations on a test in different "modes" but hopefully it is minimal enough.
The text was updated successfully, but these errors were encountered:
Describe the bug
With
shouldRedirectStdOut
enabled, Windows can hang on writing to std::cerrExpected behavior
No hangs should happen
Reproduction steps
Steps to reproduce the bug.
This is a really obnoxious one to track down but I was able to create a reproduction that reproduces it....sometimes (catch_repro.zip). You can run CMake on it to generate a visual studio project and then run the resulting exe with the
-r quiet
argument. You'll know if it hits the actual issue if the program is hung and attaching a debugger reveals that it is blocked with the following stack trace (I had better luck today running from the command prompt and then using visual studio to attach a debugger once I saw it hanging):Platform information:
Additional context
The underlying issue here, in my opinion, is a weird decision by the Microsoft C++ runtime. Whenever you write to some sort of stream, the underlying rdbuf is locked and then unlocked when the write is done. Seems sane enough except that the way it does it is by asking the stream for its rdbuf in the constructor, locking it, and then asking the stream for its rdbuf again in the destructor and unlocking that. My theory is that since Catch is so wildly swapping the rdbuf back and forth, it might be switching the rdbuf between the constructor and destructor while another thread is writing and thus causing the original rdbuf to be locked forever. I experimented by having catch do the same locking when swapping the rdbuf but that did not solve the issue. In fact the only thing that DOES work is commenting out the stopRedirect logic so that only startRedirect actually does anything. Everything I want to be logged is still logged due to Catch using
Catch::cout()
instead ofstd::cout
to log so I am willing to patch it that way, but this problem is bothering me quite a bit.Sorry this isn't quite a minimal project as it uses a custom reporter (slightly altered console reporter) and a custom invoker to allow variations on a test in different "modes" but hopefully it is minimal enough.
The text was updated successfully, but these errors were encountered: