[libcxx-commits] [libcxx] [libc++] Work around benign initialization order fiasco in locale (PR #73533)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Mon Nov 27 08:04:15 PST 2023


https://github.com/ldionne created https://github.com/llvm/llvm-project/pull/73533

Technically, it is possible for the ios initializers to run before the initializer of classic_locale_imp_, which would cause `.emplace` to be called on a not-yet-initialized __no_destroy variable.

This patch fixes that by making the variable trivially constinit, since we're not doing anything in its constructor anyway.

>From 8484ff20ad032812ffbc46bfe6d769ddba0a5acf Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 27 Nov 2023 11:01:35 -0500
Subject: [PATCH] [libc++] Work around benign initialization order fiasco in
 locale

Technically, it is possible for the ios initializers to run before
the initializer of classic_locale_imp_, which would cause `.emplace`
to be called on a not-yet-initialized __no_destroy variable.

This patch fixes that by making the variable trivially constinit,
since we're not doing anything in its constructor anyway.
---
 libcxx/include/__utility/no_destroy.h | 13 +++++++------
 libcxx/src/locale.cpp                 |  2 +-
 2 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/libcxx/include/__utility/no_destroy.h b/libcxx/include/__utility/no_destroy.h
index c8581cf9606b571..fc936d2d287316a 100644
--- a/libcxx/include/__utility/no_destroy.h
+++ b/libcxx/include/__utility/no_destroy.h
@@ -28,22 +28,23 @@ struct __uninitialized_tag {};
 // initialization using __emplace.
 template <class _Tp>
 struct __no_destroy {
-  _LIBCPP_HIDE_FROM_ABI explicit __no_destroy(__uninitialized_tag) {}
-  _LIBCPP_HIDE_FROM_ABI ~__no_destroy() {
+  _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI explicit __no_destroy(__uninitialized_tag) {}
+  _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI ~__no_destroy() {
     // nothing
   }
 
   template <class... _Args>
-  _LIBCPP_HIDE_FROM_ABI explicit __no_destroy(_Args&&... __args) : __obj_(std::forward<_Args>(__args)...) {}
+  _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI explicit __no_destroy(_Args&&... __args)
+      : __obj_(std::forward<_Args>(__args)...) {}
 
   template <class... _Args>
-  _LIBCPP_HIDE_FROM_ABI _Tp& __emplace(_Args&&... __args) {
+  _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI _Tp& __emplace(_Args&&... __args) {
     new (&__obj_) _Tp(std::forward<_Args>(__args)...);
     return __obj_;
   }
 
-  _LIBCPP_HIDE_FROM_ABI _Tp& __get() { return __obj_; }
-  _LIBCPP_HIDE_FROM_ABI _Tp const& __get() const { return __obj_; }
+  _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI _Tp& __get() { return __obj_; }
+  _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI _Tp const& __get() const { return __obj_; }
 
 private:
   union {
diff --git a/libcxx/src/locale.cpp b/libcxx/src/locale.cpp
index 2cb75f81b36da33..d6ba490a00a1109 100644
--- a/libcxx/src/locale.cpp
+++ b/libcxx/src/locale.cpp
@@ -546,7 +546,7 @@ locale::__imp::use_facet(long id) const
 // expensive in parallel applications. The classic locale is used by default
 // in all streams. Note: if a new global locale is installed, then we lose
 // the benefit of no reference counting.
-__no_destroy<locale::__imp> locale::__imp::classic_locale_imp_(__uninitialized_tag{}); // initialized below in classic()
+constinit __no_destroy<locale::__imp> locale::__imp::classic_locale_imp_(__uninitialized_tag{}); // initialized below in classic()
 
 const locale& locale::classic() {
   static const __no_destroy<locale> classic_locale(__private_tag{}, [] {



More information about the libcxx-commits mailing list