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

--- Comment #14 from Nicholas Williams <nicholas at nicholaswilliams dot net> 
---
(In reply to Jonathan Wakely from comment #11)
> (In reply to Nicholas Williams from comment #0)
> > Created attachment 60437 [details]
> > Minimal reproduction application
> > 
> > I have discovered a SIGABRT (or, when ASAN is enabled, a heap-use-after-free
> > report) in std::chrono::locate_zone() when it calls
> > std::chrono::tzdb_list::begin() as a result of C++20 Chrono library use
> > during application shutdown (exit handlers). I'm not able to attach our
> > proprietary code, so I have attached a fully functional minimal replication
> > application that successfully demonstrates the problem.
> 
> Doesn't your minimized program have a data race on the _running member?

It probably does have a race condition on _running, yes. I was not being as
careful about correctness writing this minimal replication program as I
normally am. That said, it works okay in this case and isn't what's triggering
the bug (our production code does not work as simplistically as this thread
loop).

> _pInstance is also accessed without synchronization but is only accessed
> from the main thread so that doesn't have a data race.

Yeah, it should be more like this. Again, sloppy on my part:

instance() noexcept
{
  if ( BackgroundThread::_pInstance )
  {
    return BackgroundThread::_pInstance;
  }

  {
    std::unique_lock< std::mutex > lock( BackgroundThread::_instanceMutex );
    if ( !BackgroundThread::_pInstance )
    {
      BackgroundThread::_pInstance = std::make_shared< BackgroundThread >();
    }
  }
  return BackgroundThread::_pInstance;
}

>  
> > From what I can tell reading through the ASAN report and the code in the
> > chrono header, the problem appears to be related to the use of a chrono
> > class's private static class data member that's a shared_ptr, without any
> > checks about the validity of said shared_ptr. Since static class data
> > members are destructed before static global variables,
> 
> Are they? Where is that specified?

I have definitely read that before, but cannot find it now that I need it. I
could have misunderstood what I read at the time.

> 
> > the shared_ptr in
> > chrono gets destructed before our logging thread shared_ptr.
> 
> Like all objects with static storage duration, it gets destroyed in reverse
> order of construction.
> 
> Because your logging thread shared_ptr is created early, before main, it is
> constructed in an unspecified order compared to any other globals, including
> the tzdb_list pointer. As Andrew said, there's a static initialization order
> bug.
> 
> This should be fixable by using __attribute__((init_priority(x))) inside
> libstdc++.

init_priority looks neat. That could indeed resolve this issue.

Reply via email to