[committed] libstdc++: Fix std::match_results::end() for failed matches [PR102667]

Message ID YWSSc6nznjEKec33@redhat.com
State New
Headers show
Series
  • [committed] libstdc++: Fix std::match_results::end() for failed matches [PR102667]
Related show

Commit Message

Jason Merrill via Gcc-patches Oct. 11, 2021, 7:37 p.m.
The end() function needs to consider whether the underlying vector is
empty, not whether the match_results object is empty. That's because the
underlying vector will always contain at least three elements for a
match_results object that is "ready". It contains three extra elements
which are stored in the vector but are not considered part of sequence,
and so should not be part of the [begin(),end()) range.

libstdc++-v3/ChangeLog:

	PR libstdc++/102667
	* include/bits/regex.h (match_result::empty()): Optimize by
	calling the base function directly.
	(match_results::end()): Check _Base_type::empty() not empty().
	* testsuite/28_regex/match_results/102667.C: New test.

Tested powerpc64le-linux. Committed to trunk.
commit 84088dc4bb6a546c896a068dc201463493babf43
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Oct 11 09:07:15 2021

    libstdc++: Fix std::match_results::end() for failed matches [PR102667]
    
    The end() function needs to consider whether the underlying vector is
    empty, not whether the match_results object is empty. That's because the
    underlying vector will always contain at least three elements for a
    match_results object that is "ready". It contains three extra elements
    which are stored in the vector but are not considered part of sequence,
    and so should not be part of the [begin(),end()) range.
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/102667
            * include/bits/regex.h (match_result::empty()): Optimize by
            calling the base function directly.
            (match_results::end()): Check _Base_type::empty() not empty().
            * testsuite/28_regex/match_results/102667.C: New test.

Patch

diff --git a/libstdc++-v3/include/bits/regex.h b/libstdc++-v3/include/bits/regex.h
index ff908da3e94..bf02bff7c49 100644
--- a/libstdc++-v3/include/bits/regex.h
+++ b/libstdc++-v3/include/bits/regex.h
@@ -1828,7 +1828,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
        */
       _GLIBCXX_NODISCARD bool
       empty() const noexcept
-      { return size() == 0; }
+      { return _Unchecked::size() <= 3; }
 
       ///@}
 
@@ -1946,7 +1946,7 @@  _GLIBCXX_BEGIN_NAMESPACE_CXX11
        */
       const_iterator
       end() const noexcept
-      { return _Base_type::end() - (empty() ? 0 : 3); }
+      { return _Base_type::end() - (_Base_type::empty() ? 0 : 3); }
 
       /**
        * @brief Gets an iterator to one-past-the-end of the collection.
diff --git a/libstdc++-v3/testsuite/28_regex/match_results/102667.C b/libstdc++-v3/testsuite/28_regex/match_results/102667.C
new file mode 100644
index 00000000000..9e38c9edaa4
--- /dev/null
+++ b/libstdc++-v3/testsuite/28_regex/match_results/102667.C
@@ -0,0 +1,39 @@ 
+// { dg-do run { target c++11 } }
+
+#include <regex>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::cmatch sm;
+  VERIFY( sm.empty() );
+  VERIFY( sm.size() == 0 );
+  VERIFY( sm.begin() == sm.end() );  // PR libstdc++/83600
+
+  bool matched = std::regex_match("a", sm, std::regex("b"));
+  VERIFY( ! matched );
+  VERIFY( sm.ready() );
+  VERIFY( sm.empty() );
+  VERIFY( sm.size() == 0 );
+  VERIFY( sm.begin() == sm.end() ); // PR libstdc++/102667
+
+  matched = std::regex_match("a", sm, std::regex("a"));
+  VERIFY( matched );
+  VERIFY( sm.ready() );
+  VERIFY( ! sm.empty() );
+  VERIFY( sm.size() == 1 );
+  VERIFY( (sm.end() - sm.begin()) == 1 );
+
+  matched = std::regex_search("abcd", sm, std::regex("(b)(c)"));
+  VERIFY( matched );
+  VERIFY( sm.ready() );
+  VERIFY( ! sm.empty() );
+  VERIFY( sm.size() == 3 );
+  VERIFY( (sm.end() - sm.begin()) == 3 );
+}
+
+int main()
+{
+  test01();
+}