From f52b47eea4c5de553d202669f91e6f4f14668592 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Mon, 1 Jul 2019 23:35:27 +0300 Subject: Add workaround for data race in libstdc++'s locale(const locale&, Facet*) constructor --- build2/test/script/regex.cxx | 35 +++++++++++++++++++++++++++++++++-- build2/test/script/regex.hxx | 7 +++++++ build2/test/script/regex.test.cxx | 3 ++- 3 files changed, 42 insertions(+), 3 deletions(-) (limited to 'build2/test/script') diff --git a/build2/test/script/regex.cxx b/build2/test/script/regex.cxx index 6b15266..bbd1738 100644 --- a/build2/test/script/regex.cxx +++ b/build2/test/script/regex.cxx @@ -2,6 +2,8 @@ // copyright : Copyright (c) 2014-2019 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file +#include + #include using namespace std; @@ -163,11 +165,40 @@ namespace build2 // line_char_locale // + + // An exemplar locale with the std::ctype facet. It is + // used for the subsequent line char locale objects creation (see + // below) which normally ends up with a shallow copy of a reference- + // counted object. + // + // Note that creating the line char locales from the exemplar is not + // merely an optimization: there is a data race in the libstdc++ (at + // least as of GCC 9.1) implementation of the locale(const locale&, + // Facet*) constructor (bug #91057). + // + // Also note that we install the facet in init() rather than during + // the object creation to avoid a race with the std::locale-related + // global variables initialization. + // + static locale line_char_locale_exemplar; + + void + init () + { + line_char_locale_exemplar = + locale (locale (), + new std::ctype ()); // Hidden by ctype bitmask. + } + line_char_locale:: line_char_locale () - : locale (locale (), - new std::ctype ()) // Hidden by ctype bitmask. + : locale (line_char_locale_exemplar) { + // Make sure init() has been called. + // + // Note: has_facet() is hidden by a private function in libc++. + // + assert (std::has_facet> (*this)); } // char_regex diff --git a/build2/test/script/regex.hxx b/build2/test/script/regex.hxx index 500c21b..33a4cba 100644 --- a/build2/test/script/regex.hxx +++ b/build2/test/script/regex.hxx @@ -344,6 +344,13 @@ namespace build2 // line_char_locale (); }; + + // Initialize the testscript regex global state. Should be called once + // prior to creating objects of types from this namespace. Note: not + // thread-safe. + // + void + init (); } } } diff --git a/build2/test/script/regex.test.cxx b/build2/test/script/regex.test.cxx index 7b89e4d..1e48f97 100644 --- a/build2/test/script/regex.test.cxx +++ b/build2/test/script/regex.test.cxx @@ -19,6 +19,8 @@ main () using cf = char_flags; using cr = char_regex; + init (); // Initializes the testscript regex global state. + // Test line_char. // { @@ -183,7 +185,6 @@ main () using ct = ctype; line_char_locale l; - assert (has_facet (l)); // It is better not to create q facet on stack as it is // reference-countable. -- cgit v1.1