]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Fix std::basic_stringbuf::str()&& [PR123100]
authorJonathan Wakely <jwakely@redhat.com>
Mon, 15 Dec 2025 10:25:52 +0000 (10:25 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Wed, 7 Jan 2026 15:21:52 +0000 (15:21 +0000)
When basic_stringbuf::setbuf has been called we need to copy the
contents of the buffer into _M_string first, before returning that.

libstdc++-v3/ChangeLog:

PR libstdc++/123100
* include/std/sstream (basic_stringbuf::str()&&): Handle the
case where _M_string is not being used for the buffer.
* testsuite/27_io/basic_stringbuf/str/char/123100.cc: New test.

Reviewed-by: Tomasz KamiƄski <tkaminsk@redhat.com>
libstdc++-v3/include/std/sstream
libstdc++-v3/testsuite/27_io/basic_stringbuf/str/char/123100.cc [new file with mode: 0644]

index 4a5c090f97ba3238197ad5a89d15a6d20cf60297..421c1f744b3d81f3919d92c37c30e39e97e1dfba 100644 (file)
@@ -298,7 +298,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
 #if __cplusplus > 201703L
 #if _GLIBCXX_USE_CXX11_ABI
 #if __cpp_concepts
-       // P0407 Allocator-aware basic_streambuf
+      // P0407 Allocator-aware basic_streambuf
       template<__allocator_like _SAlloc>
        _GLIBCXX_NODISCARD
        basic_string<_CharT, _Traits, _SAlloc>
@@ -315,8 +315,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       {
        if (char_type* __hi = _M_high_mark())
          {
-           // Set length to end of character sequence and add null terminator.
-           _M_string._M_set_length(_M_high_mark() - this->pbase());
+           if (_M_string.data() == this->pbase()) [[likely]]
+             // Set length to end of sequence and add null terminator.
+             _M_string._M_set_length(__hi - this->pbase());
+           else
+             _M_string.assign(this->pbase(), __hi);
          }
        auto __str = std::move(_M_string);
        _M_string.clear();
diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/str/char/123100.cc b/libstdc++-v3/testsuite/27_io/basic_stringbuf/str/char/123100.cc
new file mode 100644 (file)
index 0000000..174fe0e
--- /dev/null
@@ -0,0 +1,58 @@
+// { dg-do run }
+
+#include <sstream>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  const int n = 20;
+  const char data[n] = "abcde";
+  char buf[n] = "0123456789";
+  std::string expected("abcde56789\0\0\0\0\0\0\0\0\0\0", n);
+
+  std::ostringstream out;
+  out.rdbuf()->pubsetbuf(buf, n);
+  out << data;
+  VERIFY( out.str() == expected );
+  VERIFY( out.str() == expected );
+#if __cplusplus >= 201103L
+  VERIFY( std::move(out).str() == expected );
+#if __cplusplus >= 202002L && _GLIBCXX_USE_CXX11_ABI
+  expected.clear();
+#endif
+  VERIFY( out.str() == expected );
+  VERIFY( std::move(out).str() == expected );
+#endif
+}
+
+void
+test02()
+{
+  const int n = 20;
+  const char data[n] = "abcde";
+  char buf[n] = "0123456789";
+  std::string expected("abcde56789\0\0\0\0\0\0\0\0\0\0", n);
+
+  std::ostringstream out;
+  out << std::string(n * 2, 'a');
+  VERIFY( out.str() == std::string(n * 2, 'a') );
+  out.rdbuf()->pubsetbuf(buf, n);
+  out << data; // writes 6 chars
+  VERIFY( out.str() == expected );
+  VERIFY( out.str() == expected );
+#if __cplusplus >= 201103L
+  VERIFY( std::move(out).str() == expected );
+#if __cplusplus >= 202002L && _GLIBCXX_USE_CXX11_ABI
+  expected.clear();
+#endif
+  VERIFY( out.str() == expected );
+  VERIFY( std::move(out).str() == expected );
+#endif
+}
+
+int main()
+{
+  test01();
+  test02();
+}