From: Jonathan Wakely <[email protected]>
Tested on x86_64-pc-linux-gnu. Patch originally written by Jonathan and
completed by me (mainly testsuite adjustments).
I don't understand the stringbuf API enough to determine what the
correct value of egptr() - eback() (i.e. the get area size) should be in
the 26250.cc tests aftering calling overflow(). It's currently zero
after this patch, which I'm pretty sure is wrong?
[stringbuf.virtuals]/8 says: If ios_base::in is set in mode, the
function alters the read end pointer egptr() to point just past the new
write position.
In light of that I guess egptr() - eback() should still be 1 after this
patch then? That'd require making stringbuf::overflow() more
consistently set egptr() I believe.
But then what about for:
buf.sputn("01234567890abcdef", 16); // Exceed SSO buffer
buf.overflow('x');
VERIFY( buf.egptr() - buf.eback() == ? );
I would think the get area size should be 17? But other implementations
including us before this patch say 16, so I'm pretty confused.
-- >8 --
LWG 2995 allows us to use the SSO std::string's short string buffer as
the initial put area for a stringbuf. This avoids a call to overflow for
the first char written to an ostringstream, because the put area
consists of 15 chars immediately after construction.
PR libstdc++/80676
libstdc++-v3/ChangeLog:
* include/std/sstream (basic_stringbuf::basic_stringbuf())
[_GLIBCXX_USE_CXX11_ABI]: Call _M_stringbuf_init to use SSO buffer.
(basic_stringbuf::basic_stringbuf(openmode))
[_GLIBCXX_USE_CXX11_ABI]: Likewise.
* testsuite/27_io/basic_stringbuf/cons/80676.cc: New.
* testsuite/27_io/basic_stringbuf/cons/char/1.cc: Adjust call to
check_pointers.
* testsuite/27_io/basic_stringbuf/cons/wchar_t/1.cc: Likewise.
* testsuite/27_io/basic_stringbuf/overflow/char/26250.cc
[_GLIBCXX_USE_CXX11_ABI]: Adjust get area size assert.
* testsuite/27_io/basic_stringbuf/overflow/wchar_t/26250.cc
[_GLIBCXX_USE_CXX11_ABI]: Likewise.
* testsuite/27_io/basic_stringbuf/sputc/char/9404-1.cc
[_GLIBCXX_USE_CXX11_ABI]: Don't expected overflow() to be
called.
* testsuite/27_io/basic_stringbuf/sputc/wchar_t/9404-1.cc
[_GLIBCXX_USE_CXX11_ABI]: Likewise.
* testsuite/27_io/basic_stringbuf/sputn/char/9404-2.cc
[_GLIBCXX_USE_CXX11_ABI]: Likewise.
* testsuite/util/testsuite_io.h (constraint_buf::check_pointers):
Add defaulted is_stringbuf bool parameter. Expect non-null
instead of null pointers when DR 2995 applies.
Co-authored-by: Patrick Palka <[email protected]>
---
libstdc++-v3/include/std/sstream | 12 +++++++--
.../27_io/basic_stringbuf/cons/80676.cc | 26 +++++++++++++++++++
.../27_io/basic_stringbuf/cons/char/1.cc | 2 +-
.../27_io/basic_stringbuf/cons/wchar_t/1.cc | 2 +-
.../basic_stringbuf/overflow/char/26250.cc | 4 +++
.../basic_stringbuf/overflow/wchar_t/26250.cc | 4 +++
.../basic_stringbuf/sputc/char/9404-1.cc | 4 +++
.../basic_stringbuf/sputc/wchar_t/9404-1.cc | 4 +++
.../basic_stringbuf/sputn/char/9404-2.cc | 4 +++
libstdc++-v3/testsuite/util/testsuite_io.h | 10 ++++++-
10 files changed, 67 insertions(+), 5 deletions(-)
create mode 100644 libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/80676.cc
diff --git a/libstdc++-v3/include/std/sstream b/libstdc++-v3/include/std/sstream
index b1b41260ce3d..10fbaf00c084 100644
--- a/libstdc++-v3/include/std/sstream
+++ b/libstdc++-v3/include/std/sstream
@@ -128,7 +128,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
*/
basic_stringbuf()
: __streambuf_type(), _M_mode(ios_base::in | ios_base::out), _M_string()
- { }
+ {
+#if _GLIBCXX_USE_CXX11_ABI
+ _M_stringbuf_init(_M_mode);
+#endif
+ }
/**
* @brief Starts with an empty string buffer.
@@ -140,7 +144,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
explicit
basic_stringbuf(ios_base::openmode __mode)
: __streambuf_type(), _M_mode(__mode), _M_string()
- { }
+ {
+#if _GLIBCXX_USE_CXX11_ABI
+ _M_stringbuf_init(__mode);
+#endif
+ }
/**
* @brief Starts with an existing string buffer.
diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/80676.cc
b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/80676.cc
new file mode 100644
index 000000000000..efdac03c366d
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/80676.cc
@@ -0,0 +1,26 @@
+// { dg-do run { target c++11 } }
+// { dg-require-effective-target cxx11_abi }
+
+// PR libstdc++/80676
+// [DR 2995] basic_stringbuf does not use initial capacity of SSO string
+
+#include <sstream>
+#include <testsuite_hooks.h>
+
+int counter;
+
+struct SB : std::stringbuf
+{
+ int_type overflow(int_type c) override
+ {
+ ++counter;
+ return std::stringbuf::overflow(c);
+ }
+};
+
+int main()
+{
+ SB sb;
+ sb.sputc('a');
+ VERIFY( counter == 0 );
+}
diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/1.cc
b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/1.cc
index 78aca7730136..43f8bd1c933d 100644
--- a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/1.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/char/1.cc
@@ -27,7 +27,7 @@
void test01()
{
__gnu_test::constraint_stringbuf sbuf;
- VERIFY( sbuf.check_pointers() );
+ VERIFY( sbuf.check_pointers(/*is_stringbuf=*/true) );
}
void test02()
diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/1.cc
b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/1.cc
index 5d40df9fe395..aa833026aff4 100644
--- a/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/1.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/cons/wchar_t/1.cc
@@ -27,7 +27,7 @@
void test01()
{
__gnu_test::constraint_wstringbuf sbuf;
- VERIFY( sbuf.check_pointers() );
+ VERIFY( sbuf.check_pointers(/*is_stringbuf=*/true) );
}
void test02()
diff --git
a/libstdc++-v3/testsuite/27_io/basic_stringbuf/overflow/char/26250.cc
b/libstdc++-v3/testsuite/27_io/basic_stringbuf/overflow/char/26250.cc
index 3cb3adea70b7..1b80857d2520 100644
--- a/libstdc++-v3/testsuite/27_io/basic_stringbuf/overflow/char/26250.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/overflow/char/26250.cc
@@ -45,7 +45,11 @@ void test01()
VERIFY( write_positions > 1 );
// 27.7.1.3, p8:
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( buf.egptr() - buf.eback() == 0 );
+#else
VERIFY( buf.egptr() - buf.eback() == 1 );
+#endif
}
int main()
diff --git
a/libstdc++-v3/testsuite/27_io/basic_stringbuf/overflow/wchar_t/26250.cc
b/libstdc++-v3/testsuite/27_io/basic_stringbuf/overflow/wchar_t/26250.cc
index be0bc14e5055..75de48bc84f1 100644
--- a/libstdc++-v3/testsuite/27_io/basic_stringbuf/overflow/wchar_t/26250.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/overflow/wchar_t/26250.cc
@@ -45,7 +45,11 @@ void test01()
VERIFY( write_positions > 1 );
// 27.7.1.3, p8:
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( buf.egptr() - buf.eback() == 0 );
+#else
VERIFY( buf.egptr() - buf.eback() == 1 );
+#endif
}
int main()
diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/sputc/char/9404-1.cc
b/libstdc++-v3/testsuite/27_io/basic_stringbuf/sputc/char/9404-1.cc
index d5481eacfb3b..05d3bee8d499 100644
--- a/libstdc++-v3/testsuite/27_io/basic_stringbuf/sputc/char/9404-1.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/sputc/char/9404-1.cc
@@ -53,7 +53,11 @@ void test04()
Derived_stringbuf dsbuf_01;
over_called = false;
dsbuf_01.sputc('i');
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( !over_called ); // DR 2995 lets us strengthen this
+#else
VERIFY( over_called );
+#endif
over_expected = dsbuf_01.pub_epptr() == dsbuf_01.pub_pptr();
over_called = false;
dsbuf_01.sputc('v');
diff --git
a/libstdc++-v3/testsuite/27_io/basic_stringbuf/sputc/wchar_t/9404-1.cc
b/libstdc++-v3/testsuite/27_io/basic_stringbuf/sputc/wchar_t/9404-1.cc
index 48bcefc312e9..18f86d8f87e8 100644
--- a/libstdc++-v3/testsuite/27_io/basic_stringbuf/sputc/wchar_t/9404-1.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/sputc/wchar_t/9404-1.cc
@@ -53,7 +53,11 @@ void test04()
Derived_stringbuf dsbuf_01;
over_called = false;
dsbuf_01.sputc(L'i');
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( !over_called ); // DR 2995 lets us strengthen this
+#else
VERIFY( over_called );
+#endif
over_expected = dsbuf_01.pub_epptr() == dsbuf_01.pub_pptr();
over_called = false;
dsbuf_01.sputc(L'v');
diff --git a/libstdc++-v3/testsuite/27_io/basic_stringbuf/sputn/char/9404-2.cc
b/libstdc++-v3/testsuite/27_io/basic_stringbuf/sputn/char/9404-2.cc
index bd0aa86e03cf..a7b06f825d6a 100644
--- a/libstdc++-v3/testsuite/27_io/basic_stringbuf/sputn/char/9404-2.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_stringbuf/sputn/char/9404-2.cc
@@ -54,7 +54,11 @@ void test04()
Derived_stringbuf dsbuf_02;
over_called = false;
dsbuf_02.sputn("sonne's", 7);
+#if _GLIBCXX_USE_CXX11_ABI
+ VERIFY( !over_called ); // DR 2995 lets us strengthen this
+#else
VERIFY( over_called );
+#endif
over_expected = dsbuf_02.pub_epptr() == dsbuf_02.pub_pptr();
over_called = false;
dsbuf_02.sputn(" peak", 5);
diff --git a/libstdc++-v3/testsuite/util/testsuite_io.h
b/libstdc++-v3/testsuite/util/testsuite_io.h
index f4dca68117d6..797d11c905b8 100644
--- a/libstdc++-v3/testsuite/util/testsuite_io.h
+++ b/libstdc++-v3/testsuite/util/testsuite_io.h
@@ -68,7 +68,7 @@ namespace __gnu_test
}
bool
- check_pointers()
+ check_pointers(bool is_stringbuf = false)
{
bool one = this->eback() == 0;
bool two = this->gptr() == 0;
@@ -77,6 +77,14 @@ namespace __gnu_test
bool four = this->pbase() == 0;
bool five = this->pptr() == 0;
bool six = this->epptr() == 0;
+#if _GLIBCXX_USE_CXX11_ABI
+ if (is_stringbuf)
+ // DR 2995 made it implementation-defined whether the sequence
pointers
+ // (eback(), gptr(), egptr(), pbase(), pptr(), epptr()) are
initialized
+ // to null pointers. We initialize them to the underlying string's
+ // SSO buffer.
+ return !one && !two && !three && !four && !five && !six;
+#endif
return one && two && three && four && five && six;
}
};
--
2.51.1.549.g4e98b730f1