When linking statically to libstdc++.a (or to libstdc++_nonshared.a in
the RHEL devtoolset compiler) there's a static initialization order
problem where user code might be constructed before the
std::chrono::tzdb_list globals, and so might try to use them after
they've already been destroyed.
Use the init_priority attribute on those globals so that they are
initialized early. Since r15-7511-g4e7f74225116e7 we can disable the
warnings for using a reserved priority using a diagnostic pragma.
libstdc++-v3/ChangeLog:
PR libstdc++/118811
* src/c++20/tzdb.cc (tzdb_list::_Node): Use init_priority
attribute on static data members.
* testsuite/std/time/tzdb_list/pr118811.cc: New test.
---
Tested x86_64-linux. Pushed to trunk.
This needs to be backported too, but will have to use the system header
hack to use the attribute without warnings.
libstdc++-v3/src/c++20/tzdb.cc | 11 +++++---
.../testsuite/std/time/tzdb_list/pr118811.cc | 25 +++++++++++++++++++
2 files changed, 32 insertions(+), 4 deletions(-)
create mode 100644 libstdc++-v3/testsuite/std/time/tzdb_list/pr118811.cc
diff --git a/libstdc++-v3/src/c++20/tzdb.cc b/libstdc++-v3/src/c++20/tzdb.cc
index 7e8cce7ce8c..c3bb6a12ccc 100644
--- a/libstdc++-v3/src/c++20/tzdb.cc
+++ b/libstdc++-v3/src/c++20/tzdb.cc
@@ -133,6 +133,8 @@ namespace std::chrono
// of this type gives them access to the private members of time_zone
// and tzdb, without needing them declared in the <chrono> header.
+ // The tzdb_list singleton. This doesn't contain the actual linked list,
+ // but it has member functions that give access to it.
static tzdb_list _S_the_list;
#if USE_ATOMIC_SHARED_PTR
@@ -177,15 +179,16 @@ namespace std::chrono
// Implementation of the private constructor used for the singleton object.
constexpr tzdb_list::tzdb_list(nullptr_t) { }
- // The tzdb_list singleton. This doesn't contain the actual linked list,
- // but it has member functions that give access to it.
+#pragma GCC diagnostic ignored "-Wprio-ctor-dtor"
+
+ [[gnu::init_priority(99)]]
constinit tzdb_list tzdb_list::_Node::_S_the_list(nullptr);
- // Shared pointer to the first Node in the list.
+ [[gnu::init_priority(99)]]
constinit tzdb_list::_Node::head_ptr
tzdb_list::_Node::_S_head_owner{nullptr};
#if USE_ATOMIC_LIST_HEAD
- // Lock-free access to the first Node in the list.
+ [[gnu::init_priority(99)]]
constinit atomic<tzdb_list::_Node*> tzdb_list::_Node::_S_head_cache{nullptr};
#endif
diff --git a/libstdc++-v3/testsuite/std/time/tzdb_list/pr118811.cc
b/libstdc++-v3/testsuite/std/time/tzdb_list/pr118811.cc
new file mode 100644
index 00000000000..3968be3f0ec
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/time/tzdb_list/pr118811.cc
@@ -0,0 +1,25 @@
+// { dg-do run { target c++20 } }
+// { dg-require-effective-target tzdb }
+// { dg-require-effective-target cxx11_abi }
+// { dg-require-static-libstdcxx }
+// { dg-additional-options "-static-libstdc++" }
+
+#include <chrono>
+
+struct Global
+{
+ Global()
+ {
+ (void) std::chrono::current_zone(); // initialize tzdb on first use
+ }
+
+ ~Global()
+ {
+ (void) std::chrono::current_zone(); // attempt to use it again on exit
+ }
+
+} global;
+
+int main()
+{
+}
--
2.48.1