https://gcc.gnu.org/g:a94bd31fd80b6a7efbe4d4c81ff195f7d81c3813
commit r16-6556-ga94bd31fd80b6a7efbe4d4c81ff195f7d81c3813 Author: Jonathan Wakely <[email protected]> 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 <[email protected]> Diff: --- libstdc++-v3/include/std/sstream | 9 ++-- .../27_io/basic_stringbuf/str/char/123100.cc | 58 ++++++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/libstdc++-v3/include/std/sstream b/libstdc++-v3/include/std/sstream index 4a5c090f97ba..421c1f744b3d 100644 --- a/libstdc++-v3/include/std/sstream +++ b/libstdc++-v3/include/std/sstream @@ -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 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(); +}
