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

            Bug ID: 91057
           Summary: Data race in locale(const locale&, Facet*) constructor
           Product: gcc
           Version: 9.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: karen.arutyunov at gmail dot com
  Target Milestone: ---

In our build2 toolchain project we instantiate std::basic_regex class template
with a custom character type (line_char) that, in particular, requires
std::regex_traits<line_char> specialization and defining a locale class that
installs the std::ctype<line_char> facet in constructor.

Objects of the regex class that inherits from std::basic_regex<line_char> are
created, used and destroyed concurrently in multiple threads but are not shared
between threads.

The problem is that while creating such an objects std::bad_cast is
sporadically thrown. Unfortunately, I'm unable to reproduce the issue in my
development environment to provide a full stack trace and, moreover, a simple
test to replicate the issue. However, debugging through the creation of these
regex objects makes me think that there is the following data race in the
libstdc++'s locale implementation that may case the described behavior.

The locale(const locale&, Facet*) constructor template (that is called from
multiple threads in our case) calls

_M_impl->_M_install_facet(&_Facet::id, __f);

that in turn calls _M_id() for the passed facet id. On the first call the
locale::id::_M_id() function sets/uses the locale::id::_M_index member in the
thread-unsafe manner:

size_t
locale::id::_M_id() const throw()
{
  if (!_M_index)
  {
    _M_index = ...
  }

  return _M_index - 1;
}

As a result, 2 locale objects created concurrently in 2 threads with the
mentioned constructor may have a facet of the same type to be saved under
different indexes in the _M_facets array. If that happens then use_facet()
template function called for this facet type will end up badly for one of the
objects, taking the facet pointer from the wrong index (may crash, throw
bad_cast, etc).

Reply via email to