From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id 50BA7384B82B; Fri, 28 Oct 2022 14:27:41 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 50BA7384B82B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1666967261; bh=WL4hSxdmwK3Lr5/cY0KxJZv6qYRvuAp9e2G2gSovKZg=; h=From:To:Subject:Date:From; b=lGJiB+zTzkjTtDV9uA9pzXieAWNDOtT5lueyAuA0dr3k0yMOgLrTcjgjWE1FpLMZI CU8qDtw0wGVtzsD4u2QOomNag8vmG1PqMCSpdj9lns6f+K7OKPZqwOXSmdhZCOBMcE aiWwaRMdY3CogptsmeW+xkZWJjbq9dUAoUiewZI4= MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r13-3548] libstdc++: Fix allocator propagation in regex algorithms [PR107376] X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: 95decac3ce8c8c7c5302cd6fac005a10463de165 X-Git-Newrev: 988dd22ec6665117e8587389ac85389f1c321c45 Message-Id: <20221028142741.50BA7384B82B@sourceware.org> Date: Fri, 28 Oct 2022 14:27:41 +0000 (GMT) List-Id: https://gcc.gnu.org/g:988dd22ec6665117e8587389ac85389f1c321c45 commit r13-3548-g988dd22ec6665117e8587389ac85389f1c321c45 Author: Jonathan Wakely Date: Tue Oct 25 13:03:12 2022 +0100 libstdc++: Fix allocator propagation in regex algorithms [PR107376] 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. Diff: --- 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(-) 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 +#include +#include + +template +struct Alloc +{ + using value_type = T; + explicit Alloc(int) { } + template Alloc(const Alloc&) { } + + T* allocate(std::size_t n) + { return std::allocator().allocate(n); } + void deallocate(T* ptr, std::size_t n) + { std::allocator().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; + using alloc_type = Alloc; + using match_results = std::match_results; + match_results res(alloc_type(1)); + + std::regex_match("x", res, std::regex(".")); // PR libstdc++/107376 +} + +template +struct PropAlloc +{ + int id; + + using value_type = T; + explicit PropAlloc(int id) : id(id) { } + template 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().allocate(n); } + void deallocate(T* ptr, std::size_t n) + { std::allocator().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; + using alloc_type = PropAlloc; + using match_results = std::match_results; + 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(); +}