On Wed, 7 Jan 2026 at 13:51, Tomasz Kaminski <[email protected]> wrote:
>
>
>
> On Wed, Jan 7, 2026 at 12:56 PM Jonathan Wakely <[email protected]> wrote:
>>
>> 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.
>> ---
>>
>> Tested x86_64-linux.
>
> LGTM. One small subjective and stylistic suggestion.
>>
>>
>> libstdc++-v3/include/std/sstream | 9 ++-
>> .../27_io/basic_stringbuf/str/char/123100.cc | 58 +++++++++++++++++++
>> 2 files changed, 64 insertions(+), 3 deletions(-)
>> create mode 100644
>> libstdc++-v3/testsuite/27_io/basic_stringbuf/str/char/123100.cc
>>
>> diff --git a/libstdc++-v3/include/std/sstream
>> b/libstdc++-v3/include/std/sstream
>> index 4a5c090f97ba..f036165909df 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.c_str() == this->pbase()) [[likely]]
>
> I would preffer _M_string.data(), as we are already in C++17 mode.
Good idea. That's what's used later in the function too.
>>
>> + // 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();
>> +}
>> --
>> 2.52.0
>>