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

            Bug ID: 118811
           Summary: SIGABRT (or ASAN heap-use-after-free) in
                    chrono::locate_zone--chrono::tzdb_list during exit
                    handlers
           Product: gcc
           Version: 14.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: nicholas at nicholaswilliams dot net
  Target Milestone: ---

Created attachment 60437
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=60437&action=edit
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.

If it helps, I can say that our exact use case involves an internal logging
library that uses a background std::thread to flush log events to their
intended destination(s). This is done because our real-time application
behavior is very performance sensitive and we don't want anything to be blocked
by log flushes. The background thread is kept alive until the very latest
moment possible to avoid losing log events.

I thought it would be useful to have the details from a system on which the bug
does not occur (Ubuntu 24.04 with GCC 13.3.0) to compare against the details
from a system on which the bug does occur (RHEL 9 with GCC 14.2.1), so I have
attached the .ii files, "-v" compile output, and runtime output from *both*
systems. (Or at least, I'm going to try to. It seems to only allow me to attach
a single file, so I'm going to try to attach additional files after creating
this.) Apologies if this is too much or not any more helpful than had I just
attached the files from the buggy system.

I compiled on both systems with this command/these options:

$ g++ -v -save-temps -std=c++20 -fsanitize=address
-fsanitize-address-use-after-scope -Wall -Wextra -Werror -D_GLIBCXX_ASSERTIONS
-D_GLIBCXX_DEBUG -o gcc_chrono_segfault gcc_chrono_segfault.cpp

The "-D_GLIBCXX_ASSERTIONS -D_GLIBCXX_DEBUG" was added as instructed in the bug
reporting instructions. Without those, the behavior is identical (still works
with GCC 13, still fails with GCC 14). The use of Address Sanitizer here is
because it provides substantial details about the source of the problem, but
without it the application still fails with SIGABRT (134).

I don't claim to be an expert on the C++ specification, but my understanding is
that since it is not explicitly stated that time zones are unsafe to use during
exit handlers, they should be safe to use during exit handlers. We certainly
haven't had a problem using any other C++ features (I/O streams, threads,
strings, even other chrono features).

>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, the shared_ptr in chrono gets destructed before
our logging thread shared_ptr. In my opinion, this data should either be stored
in some more-durable (longer-living) way, or it should be re-loaded if the
shared_ptr is found to be invalid. Perhaps, even, there should be some kind of
fallback plan. I'm not certain on the best course of action.

In our case, we were previously using gmtime_r, std::put_time, etc. to format
our timestamp, so our workaround for this problem is to revert the change we
made that took advantage of this new C++20 Chrono feature. I've been unable to
devise any other kind of workaround that still allows us to use
std::chrono::time_zone.

Happy to provide any more information or try any other things as needed. Just
ask.

Reply via email to