https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111676

            Bug ID: 111676
           Summary: Race condition in std::ios::Init
           Product: gcc
           Version: 14.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: redi at gcc dot gnu.org
  Target Milestone: ---

#include <ios>
#include <thread>

void f() { std::ios::Init i; }

int main()
{
  std::thread t1(f);
  std::thread t2(f);
  t1.join();
  t2.join();
}

A possible execution for this program is:

t1 runs the Init constructor which increments Init::_S_refcount to 1 and
performs the one-time initialization of the global streams.
t2 runs the Init constructor and increments the refcount to 2.
t2 runs the ~Init destructor, which decrements the refcount to 1 and so flushes
the global streams (while still under construction).
t1 finishes constructing the global streams, and increments _S_refcount to 2.
t1 runs the ~Init destructor, which decrements the refcount to 1 and so flushes
the global streams again.

Flushing twice isn't a problem, but t2 should block until t1 finishes
constructing them, so that it doesn't flush objects that haven't finished
initialization yet.

We could just use a local static so that the __cxa_guard routines are used to
make the second thread block until the initialization is complete.

Reply via email to