diff options
author | Karen Arutyunov <karen@codesynthesis.com> | 2019-07-01 23:35:27 +0300 |
---|---|---|
committer | Karen Arutyunov <karen@codesynthesis.com> | 2019-07-02 16:43:57 +0300 |
commit | f52b47eea4c5de553d202669f91e6f4f14668592 (patch) | |
tree | 1f7920725b5e878883caf570b233a72e42065f1b /build2/test/script | |
parent | 1e71bf440efb037a7aa2bafd679cf988129fad7b (diff) |
Add workaround for data race in libstdc++'s locale(const locale&, Facet*) constructor
Diffstat (limited to 'build2/test/script')
-rw-r--r-- | build2/test/script/regex.cxx | 35 | ||||
-rw-r--r-- | build2/test/script/regex.hxx | 7 | ||||
-rw-r--r-- | build2/test/script/regex.test.cxx | 3 |
3 files changed, 42 insertions, 3 deletions
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 <locale> + #include <build2/test/script/regex.hxx> using namespace std; @@ -163,11 +165,40 @@ namespace build2 // line_char_locale // + + // An exemplar locale with the std::ctype<line_char> 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<line_char> ()); // Hidden by ctype bitmask. + } + line_char_locale:: line_char_locale () - : locale (locale (), - new std::ctype<line_char> ()) // 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<std::ctype<line_char>> (*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<lc>; line_char_locale l; - assert (has_facet<ct> (l)); // It is better not to create q facet on stack as it is // reference-countable. |