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/b.cxx | 2 +- build2/test/init.cxx | 10 ++++++++++ build2/test/init.hxx | 3 +++ build2/test/script/regex.cxx | 35 +++++++++++++++++++++++++++++++++-- build2/test/script/regex.hxx | 7 +++++++ build2/test/script/regex.test.cxx | 3 ++- 6 files changed, 56 insertions(+), 4 deletions(-) (limited to 'build2') diff --git a/build2/b.cxx b/build2/b.cxx index 5ea4f02..4a446ac 100644 --- a/build2/b.cxx +++ b/build2/b.cxx @@ -445,7 +445,7 @@ main (int argc, char* argv[]) config_preprocess_create = &config::preprocess_create; bm["dist"] = mf {&dist::boot, &dist::init}; - bm["test"] = mf {&test::boot, &test::init}; + bm["test"] = test::build2_test_load (); bm["install"] = mf {&install::boot, &install::init}; bm["version"] = mf {&version::boot, &version::init}; diff --git a/build2/test/init.cxx b/build2/test/init.cxx index 725d557..1f5a3ae 100644 --- a/build2/test/init.cxx +++ b/build2/test/init.cxx @@ -15,6 +15,8 @@ #include #include +#include // script::regex::init() + using namespace std; using namespace butl; @@ -217,5 +219,13 @@ namespace build2 return true; } + + module_functions + build2_test_load () + { + script::regex::init (); + + return module_functions {&boot, &init}; + } } } diff --git a/build2/test/init.hxx b/build2/test/init.hxx index f429645..5272a4d 100644 --- a/build2/test/init.hxx +++ b/build2/test/init.hxx @@ -25,6 +25,9 @@ namespace build2 bool, bool, const variable_map&); + + extern "C" module_functions + build2_test_load (); } } 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