summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2021-12-12 21:15:17 +0000
committerJonathan Wakely <jwakely@redhat.com>2023-06-23 13:36:31 +0100
commit364cb498c472790e14561f7672dc5ab4a9222287 (patch)
treec75276ae1774beb0a56def789598855cd94b8ce1
parentd877bf3bdf46b5c996505fc247d170e79fbfa4bf (diff)
libstdc++: Fix std::regex_replace for strings with embedded null [PR103664]
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)
-rw-r--r--libstdc++-v3/include/bits/regex.h20
-rw-r--r--libstdc++-v3/include/bits/regex.tcc9
-rw-r--r--libstdc++-v3/testsuite/28_regex/algorithms/regex_replace/char/103664.cc11
3 files changed, 33 insertions, 7 deletions
diff --git a/libstdc++-v3/include/bits/regex.h b/libstdc++-v3/include/bits/regex.h
index 3fded333d47..c7630869548 100644
--- a/libstdc++-v3/include/bits/regex.h
+++ b/libstdc++-v3/include/bits/regex.h
@@ -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,
diff --git a/libstdc++-v3/include/bits/regex.tcc b/libstdc++-v3/include/bits/regex.tcc
index 0ca4f7a7c43..5ff01d115f0 100644
--- a/libstdc++-v3/include/bits/regex.tcc
+++ b/libstdc++-v3/include/bits/regex.tcc
@@ -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
index 00000000000..ca75e49ed3e
--- /dev/null
+++ b/libstdc++-v3/testsuite/28_regex/algorithms/regex_replace/char/103664.cc
@@ -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) );
+}