[gcc r14-12590] libstdc++: Fix std::basic_stringbuf::str()&& [PR123100]

Jonathan Wakely redi@gcc.gnu.org
Thu May 14 10:09:33 GMT 2026


https://gcc.gnu.org/g:734af19063ac0a1b515083503134909b41a8b17a

commit r14-12590-g734af19063ac0a1b515083503134909b41a8b17a
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Mon Dec 15 10:25:52 2025 +0000

    libstdc++: Fix std::basic_stringbuf::str()&& [PR123100]
    
    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>
    (cherry picked from commit a94bd31fd80b6a7efbe4d4c81ff195f7d81c3813)

Diff:
---
 libstdc++-v3/include/std/sstream                   |  7 ++-
 .../27_io/basic_stringbuf/str/char/123100.cc       | 58 ++++++++++++++++++++++
 2 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/sstream b/libstdc++-v3/include/std/sstream
index dda7096afe40..d525f141fda5 100644
--- a/libstdc++-v3/include/std/sstream
+++ b/libstdc++-v3/include/std/sstream
@@ -273,8 +273,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
index 000000000000..174fe0ece1d6
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/str/char/123100.cc
@@ -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();
+}


More information about the Libstdc++-cvs mailing list