Tested powerpc64le-linux. Pushed to trunk. -- >8 --
The PR points out that we assume the match_results allocator is default constuctible, which might not be true. We also have a related issue with unwanted propagation from an object that might have an unequal allocator. Ideally we use the same allocator type for _State_info::_M_match_queue but that would be an ABI change now. We should investigate if that can be done without breaking anything, which might be possible because the _Executor object is short-lived and never leaks out of the regex_match, regex_search, and regex_replace algorithms. If we change the mangled name for _Executor then there would be no ODR violations when mixing old and new definitions. This commit does not attempt that. libstdc++-v3/ChangeLog: PR libstdc++/107376 * include/bits/regex_executor.h (_Executor::_Executor): Use same allocator for _M_cur_results and _M_results. * include/bits/regex_executor.tcc (_Executor::_M_main_dispatch): Prevent possibly incorrect allocator propagating to _M_cur_results. * testsuite/28_regex/algorithms/regex_match/107376.cc: New test. --- libstdc++-v3/include/bits/regex_executor.h | 17 +++-- libstdc++-v3/include/bits/regex_executor.tcc | 3 +- .../28_regex/algorithms/regex_match/107376.cc | 76 +++++++++++++++++++ 3 files changed, 87 insertions(+), 9 deletions(-) create mode 100644 libstdc++-v3/testsuite/28_regex/algorithms/regex_match/107376.cc diff --git a/libstdc++-v3/include/bits/regex_executor.h b/libstdc++-v3/include/bits/regex_executor.h index dc0878ce678..cdafcd5523d 100644 --- a/libstdc++-v3/include/bits/regex_executor.h +++ b/libstdc++-v3/include/bits/regex_executor.h @@ -71,14 +71,15 @@ namespace __detail _ResultsVec& __results, const _RegexT& __re, _FlagT __flags) - : _M_begin(__begin), - _M_end(__end), - _M_re(__re), - _M_nfa(*__re._M_automaton), - _M_results(__results), - _M_rep_count(_M_nfa.size()), - _M_states(_M_nfa._M_start(), _M_nfa.size()), - _M_flags(__flags) + : _M_cur_results(__results.get_allocator()), + _M_begin(__begin), + _M_end(__end), + _M_re(__re), + _M_nfa(*__re._M_automaton), + _M_results(__results), + _M_rep_count(_M_nfa.size()), + _M_states(_M_nfa._M_start(), _M_nfa.size()), + _M_flags(__flags) { using namespace regex_constants; if (__flags & match_prev_avail) // ignore not_bol and not_bow diff --git a/libstdc++-v3/include/bits/regex_executor.tcc b/libstdc++-v3/include/bits/regex_executor.tcc index b93e958075e..a5885ed34ba 100644 --- a/libstdc++-v3/include/bits/regex_executor.tcc +++ b/libstdc++-v3/include/bits/regex_executor.tcc @@ -124,9 +124,10 @@ namespace __detail break; std::fill_n(_M_states._M_visited_states, _M_nfa.size(), false); auto __old_queue = std::move(_M_states._M_match_queue); + auto __alloc = _M_cur_results.get_allocator(); for (auto& __task : __old_queue) { - _M_cur_results = std::move(__task.second); + _M_cur_results = _ResultsVec(std::move(__task.second), __alloc); _M_dfs(__match_mode, __task.first); } if (__match_mode == _Match_mode::_Prefix) diff --git a/libstdc++-v3/testsuite/28_regex/algorithms/regex_match/107376.cc b/libstdc++-v3/testsuite/28_regex/algorithms/regex_match/107376.cc new file mode 100644 index 00000000000..da4f7ad0a23 --- /dev/null +++ b/libstdc++-v3/testsuite/28_regex/algorithms/regex_match/107376.cc @@ -0,0 +1,76 @@ +// { dg-do run { target c++11 } } +#include <regex> +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +template<typename T> +struct Alloc +{ + using value_type = T; + explicit Alloc(int) { } + template<typename U> Alloc(const Alloc&) { } + + T* allocate(std::size_t n) + { return std::allocator<T>().allocate(n); } + void deallocate(T* ptr, std::size_t n) + { std::allocator<T>().deallocate(ptr, n); } + + bool operator==(const Alloc&) const { return true; } + bool operator!=(const Alloc&) const { return false; } +}; + +void +test_non_default_constructible() +{ + using sub_match = std::sub_match<const char*>; + using alloc_type = Alloc<sub_match>; + using match_results = std::match_results<const char*, alloc_type>; + match_results res(alloc_type(1)); + + std::regex_match("x", res, std::regex(".")); // PR libstdc++/107376 +} + +template<typename T> +struct PropAlloc +{ + int id; + + using value_type = T; + explicit PropAlloc(int id) : id(id) { } + template<typename U> PropAlloc(const PropAlloc& a) : id(a.id) { } + + using propagate_on_container_move_assignment = std::true_type; + using propagate_on_container_copy_assignment = std::true_type; + + PropAlloc select_on_container_copy_construction() const + { return PropAlloc(0); } + + T* allocate(std::size_t n) + { return std::allocator<T>().allocate(n); } + void deallocate(T* ptr, std::size_t n) + { std::allocator<T>().deallocate(ptr, n); } + + bool operator==(const PropAlloc& a) const { return id == a.id; } + bool operator!=(const PropAlloc& a) const { return id != a.id; } +}; + +void +test_propagation() +{ + using sub_match = std::sub_match<const char*>; + using alloc_type = PropAlloc<sub_match>; + using match_results = std::match_results<const char*, alloc_type>; + alloc_type alloc(107376); + match_results res(alloc); + + std::regex re("..", std::regex_constants::__polynomial); + std::regex_match("xx", res, re); + + VERIFY( res.get_allocator() == alloc ); +} + +int main() +{ + test_non_default_constructible(); + test_propagation(); +} -- 2.37.3