Tested x86_64-linux. -- >8 --
The current implementation of std::ios_base::Init::Init() uses an atomic reference count to ensure that the global iostreams are only initialized once. However, it doesn't ensure that other threads will wait for that initialization to finish before trying to use the streams. The reference count also doesn't ensure that only one thread flushes the streams on process exit. libstdc++-v3/ChangeLog: PR libstdc++/111676 * src/c++98/ios_init.cc (init_once): New function. (ios_base::Init::Init()): Move initialization logic to init_once and use local static initialization to call it. --- libstdc++-v3/src/c++98/ios_init.cc | 84 +++++++++++++++++------------- 1 file changed, 49 insertions(+), 35 deletions(-) diff --git a/libstdc++-v3/src/c++98/ios_init.cc b/libstdc++-v3/src/c++98/ios_init.cc index 6e2e5014cf0..14f8bb678b0 100644 --- a/libstdc++-v3/src/c++98/ios_init.cc +++ b/libstdc++-v3/src/c++98/ios_init.cc @@ -75,49 +75,63 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION extern wostream wclog; #endif - ios_base::Init::Init() +namespace +{ + bool init_once(bool* synced_with_stdio, _Atomic_word* refcount) { - if (__gnu_cxx::__exchange_and_add_dispatch(&_S_refcount, 1) == 0) - { - // Standard streams default to synced with "C" operations. - _S_synced_with_stdio = true; + // Standard streams default to synced with "C" operations. + *synced_with_stdio = true; - new (&buf_cout_sync) stdio_sync_filebuf<char>(stdout); - new (&buf_cin_sync) stdio_sync_filebuf<char>(stdin); - new (&buf_cerr_sync) stdio_sync_filebuf<char>(stderr); + new (&buf_cout_sync) stdio_sync_filebuf<char>(stdout); + new (&buf_cin_sync) stdio_sync_filebuf<char>(stdin); + new (&buf_cerr_sync) stdio_sync_filebuf<char>(stderr); - // The standard streams are constructed once only and never - // destroyed. - new (&cout) ostream(&buf_cout_sync); - new (&cin) istream(&buf_cin_sync); - new (&cerr) ostream(&buf_cerr_sync); - new (&clog) ostream(&buf_cerr_sync); - cin.tie(&cout); - cerr.setf(ios_base::unitbuf); - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 455. cerr::tie() and wcerr::tie() are overspecified. - cerr.tie(&cout); + // The standard streams are constructed once only and never + // destroyed. + new (&cout) ostream(&buf_cout_sync); + new (&cin) istream(&buf_cin_sync); + new (&cerr) ostream(&buf_cerr_sync); + new (&clog) ostream(&buf_cerr_sync); + cin.tie(&cout); + cerr.setf(ios_base::unitbuf); + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 455. cerr::tie() and wcerr::tie() are overspecified. + cerr.tie(&cout); #ifdef _GLIBCXX_USE_WCHAR_T - new (&buf_wcout_sync) stdio_sync_filebuf<wchar_t>(stdout); - new (&buf_wcin_sync) stdio_sync_filebuf<wchar_t>(stdin); - new (&buf_wcerr_sync) stdio_sync_filebuf<wchar_t>(stderr); + new (&buf_wcout_sync) stdio_sync_filebuf<wchar_t>(stdout); + new (&buf_wcin_sync) stdio_sync_filebuf<wchar_t>(stdin); + new (&buf_wcerr_sync) stdio_sync_filebuf<wchar_t>(stderr); - new (&wcout) wostream(&buf_wcout_sync); - new (&wcin) wistream(&buf_wcin_sync); - new (&wcerr) wostream(&buf_wcerr_sync); - new (&wclog) wostream(&buf_wcerr_sync); - wcin.tie(&wcout); - wcerr.setf(ios_base::unitbuf); - wcerr.tie(&wcout); + new (&wcout) wostream(&buf_wcout_sync); + new (&wcin) wistream(&buf_wcin_sync); + new (&wcerr) wostream(&buf_wcerr_sync); + new (&wclog) wostream(&buf_wcerr_sync); + wcin.tie(&wcout); + wcerr.setf(ios_base::unitbuf); + wcerr.tie(&wcout); #endif - // NB: Have to set refcount above one, so that standard - // streams are not re-initialized with uses of ios_base::Init - // besides <iostream> static object, ie just using <ios> with - // ios_base::Init objects. - __gnu_cxx::__atomic_add_dispatch(&_S_refcount, 1); - } + *refcount = 1; + + return true; + } +} // namespace + + ios_base::Init::Init() + { +#if defined(__GTHREADS) && !defined(__cpp_threadsafe_static_init) +# error "Initialization of global iostreams requires thread-safe static init" +#endif + + [[__maybe_unused__]] + static const bool init = init_once(&_S_synced_with_stdio, &_S_refcount); + + // NB: Have to set refcount above one, so that standard + // streams are not re-initialized with uses of ios_base::Init + // besides <iostream> static object, ie just using <ios> with + // ios_base::Init objects. + __gnu_cxx::__atomic_add_dispatch(&_S_refcount, 1); } ios_base::Init::~Init() -- 2.46.0