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

Reply via email to