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>
This commit is contained in:
Jonathan Wakely
2025-12-15 10:25:52 +00:00
committed by Jonathan Wakely
parent a6c853112d
commit a94bd31fd8
2 changed files with 64 additions and 3 deletions

View 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();

View File

@@ -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();
}