]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Fix std::regex_replace for strings with embedded null [PR103664]
authorJonathan Wakely <jwakely@redhat.com>
Sun, 12 Dec 2021 21:15:17 +0000 (21:15 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Fri, 23 Jun 2023 12:36:31 +0000 (13:36 +0100)
The overload of std::regex_replace that takes a std::basic_string as the
fmt argument (for the replacement string) is implemented in terms of the
one taking a const C*, which uses std::char_traits to find the length.
That means it stops at a null character, even though the basic_string
might have additional characters beyond that.

Rather than duplicate the implementation of the const C* one for the
std::basic_string case, this moves that implementation to a new
__regex_replace function which takes a const C* and a length. Then both
the std::basic_string and const C* overloads can call that (with the
latter using char_traits to find the length to pass to the new
function).

libstdc++-v3/ChangeLog:

PR libstdc++/103664
* include/bits/regex.h (__regex_replace): Declare.
(regex_replace): Use it.
* include/bits/regex.tcc (__regex_replace): Replace regex_replace
definition with __regex_replace.
* testsuite/28_regex/algorithms/regex_replace/char/103664.cc: New test.

(cherry picked from commit ef5d671cd80a4afa4f74c3dfe2904c63f51fcfde)

libstdc++-v3/include/bits/regex.h
libstdc++-v3/include/bits/regex.tcc
libstdc++-v3/testsuite/28_regex/algorithms/regex_replace/char/103664.cc [new file with mode: 0644]

index 3fded333d473f294b59849ac2b0f586f97870d72..c7630869548a637a3f6cac00af7323f475b75fbb 100644 (file)
@@ -2457,6 +2457,15 @@ _GLIBCXX_END_NAMESPACE_CXX11
                 = regex_constants::match_default) = delete;
 
   // std [28.11.4] Function template regex_replace
+
+  template<typename _Out_iter, typename _Bi_iter,
+          typename _Rx_traits, typename _Ch_type>
+    _Out_iter
+    __regex_replace(_Out_iter __out, _Bi_iter __first, _Bi_iter __last,
+                   const basic_regex<_Ch_type, _Rx_traits>& __e,
+                   const _Ch_type* __fmt, size_t __len,
+                   regex_constants::match_flag_type __flags);
+
   /**
    * @brief Search for a regular expression within a range for multiple times,
    and replace the matched parts through filling a format string.
@@ -2480,7 +2489,8 @@ _GLIBCXX_END_NAMESPACE_CXX11
                  regex_constants::match_flag_type __flags
                  = regex_constants::match_default)
     {
-      return regex_replace(__out, __first, __last, __e, __fmt.c_str(), __flags);
+      return std::__regex_replace(__out, __first, __last, __e, __fmt.c_str(),
+                                 __fmt.length(), __flags);
     }
 
   /**
@@ -2503,7 +2513,13 @@ _GLIBCXX_END_NAMESPACE_CXX11
                  const basic_regex<_Ch_type, _Rx_traits>& __e,
                  const _Ch_type* __fmt,
                  regex_constants::match_flag_type __flags
-                 = regex_constants::match_default);
+                 = regex_constants::match_default)
+    {
+      return std::__regex_replace(__out, __first, __last, __e, __fmt,
+                                 char_traits<_Ch_type>::length(__fmt),
+                                 __flags);
+    }
+
 
   /**
    * @brief Search for a regular expression within a string for multiple times,
index 0ca4f7a7c433e2bad40729f74ea60b75ed6f9c55..5ff01d115f0d7c1a14bd107fd87e42a650e3b0c7 100644 (file)
@@ -461,10 +461,10 @@ namespace __detail
   template<typename _Out_iter, typename _Bi_iter,
           typename _Rx_traits, typename _Ch_type>
     _Out_iter
-    regex_replace(_Out_iter __out, _Bi_iter __first, _Bi_iter __last,
-                 const basic_regex<_Ch_type, _Rx_traits>& __e,
-                 const _Ch_type* __fmt,
-                 regex_constants::match_flag_type __flags)
+    __regex_replace(_Out_iter __out, _Bi_iter __first, _Bi_iter __last,
+                   const basic_regex<_Ch_type, _Rx_traits>& __e,
+                   const _Ch_type* __fmt, size_t __len,
+                   regex_constants::match_flag_type __flags)
     {
       typedef regex_iterator<_Bi_iter, _Ch_type, _Rx_traits> _IterT;
       _IterT __i(__first, __last, __e, __flags);
@@ -477,7 +477,6 @@ namespace __detail
       else
        {
          sub_match<_Bi_iter> __last;
-         auto __len = char_traits<_Ch_type>::length(__fmt);
          for (; __i != __end; ++__i)
            {
              if (!(__flags & regex_constants::format_no_copy))
diff --git a/libstdc++-v3/testsuite/28_regex/algorithms/regex_replace/char/103664.cc b/libstdc++-v3/testsuite/28_regex/algorithms/regex_replace/char/103664.cc
new file mode 100644 (file)
index 0000000..ca75e49
--- /dev/null
@@ -0,0 +1,11 @@
+// { dg-do run { target c++11 } }
+
+#include <regex>
+#include <testsuite_hooks.h>
+
+int main()
+{
+  // PR libstdc++/103664
+  std::string a = regex_replace("123", std::regex("2"), std::string("a\0b", 3));
+  VERIFY( a == std::string("1a\0b3", 5) );
+}