[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 12:17:46 PST 2023
https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/73533
>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 1/3] [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{}, [] {
>From 918dc9bce13ee2f9524f3db65f733b2a383a24b5 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 27 Nov 2023 14:05:59 -0500
Subject: [PATCH 2/3] Format
---
libcxx/src/locale.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libcxx/src/locale.cpp b/libcxx/src/locale.cpp
index d6ba490a00a1109..5bd53d99ca41a48 100644
--- a/libcxx/src/locale.cpp
+++ b/libcxx/src/locale.cpp
@@ -546,7 +546,8 @@ 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.
-constinit __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{}, [] {
>From 1e35a468323e99d381c8fe3b18bf91e908058e01 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Mon, 27 Nov 2023 14:27:26 -0500
Subject: [PATCH 3/3] Initialize dummy member when constant evaluated
---
libcxx/include/__utility/no_destroy.h | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/__utility/no_destroy.h b/libcxx/include/__utility/no_destroy.h
index fc936d2d287316a..3563774301efba0 100644
--- a/libcxx/include/__utility/no_destroy.h
+++ b/libcxx/include/__utility/no_destroy.h
@@ -10,6 +10,7 @@
#define _LIBCPP___UTILITY_NO_DESTROY_H
#include <__config>
+#include <__type_traits/is_constant_evaluated.h>
#include <__utility/forward.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -28,8 +29,12 @@ struct __uninitialized_tag {};
// initialization using __emplace.
template <class _Tp>
struct __no_destroy {
- _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI explicit __no_destroy(__uninitialized_tag) {}
- _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI ~__no_destroy() {
+ _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI explicit __no_destroy(__uninitialized_tag) : __dummy_() {
+ if (__libcpp_is_constant_evaluated()) {
+ __dummy_ = char();
+ }
+ }
+ _LIBCPP_HIDE_FROM_ABI ~__no_destroy() {
// nothing
}
@@ -49,6 +54,7 @@ struct __no_destroy {
private:
union {
_Tp __obj_;
+ char __dummy_; // so we can initialize a member even with __uninitialized_tag for constexpr-friendliness
};
};
More information about the libcxx-commits
mailing list