PR libstdc++/81338 correctly manage string capacity
authorJonathan Wakely <jwakely@redhat.com>
Mon, 10 Jul 2017 17:58:56 +0000 (18:58 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Mon, 10 Jul 2017 17:58:56 +0000 (18:58 +0100)
PR libstdc++/81338
* include/bits/basic_string.h [_GLIBCXX_USE_CXX11_ABI] (basic_string):
Declare basic_stringbuf to be a friend.
* include/bits/sstream.tcc (basic_stringbuf::overflow)
[_GLIBCXX_USE_CXX11_ABI]: Use unused capacity before reallocating.
* include/std/sstream (basic_stringbuf::__xfer_bufptrs): Update string
length to buffer length.
* testsuite/27_io/basic_stringstream/assign/81338.cc: New.

From-SVN: r250100

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/basic_string.h
libstdc++-v3/include/bits/sstream.tcc
libstdc++-v3/include/std/sstream
libstdc++-v3/testsuite/27_io/basic_stringstream/assign/81338.cc [new file with mode: 0644]

index 20d80202ad76decbe5a22e65206461bcf0ca2c16..58adb85608b416d74a54d2b33e2ec8507d7a6982 100644 (file)
@@ -1,3 +1,14 @@
+2017-07-10  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/81338
+       * include/bits/basic_string.h [_GLIBCXX_USE_CXX11_ABI] (basic_string):
+       Declare basic_stringbuf to be a friend.
+       * include/bits/sstream.tcc (basic_stringbuf::overflow)
+       [_GLIBCXX_USE_CXX11_ABI]: Use unused capacity before reallocating.
+       * include/std/sstream (basic_stringbuf::__xfer_bufptrs): Update string
+       length to buffer length.
+       * testsuite/27_io/basic_stringstream/assign/81338.cc: New.
+
 2017-07-06  Jonathan Wakely  <jwakely@redhat.com>
 
        * testsuite/20_util/specialized_algorithms/memory_management_tools/
index 519d686063e1892bd9787537db3dfc1454a9be3d..7fd867c6acc759141bb9e012af0424ead3d84493 100644 (file)
@@ -2918,7 +2918,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
       int
       compare(size_type __pos, size_type __n1, const _CharT* __s,
              size_type __n2) const;
-  };
+
+      // Allow basic_stringbuf::__xfer_bufptrs to call _M_length:
+      template<typename, typename, typename> friend class basic_stringbuf;
+    };
 _GLIBCXX_END_NAMESPACE_CXX11
 #else  // !_GLIBCXX_USE_CXX11_ABI
   // Reference-counted COW string implentation
index 72e8742b4cfed8841ba3754b953a08e8f5df4115..fc2fcb8992daf8dadfa521fc7dfbb363c9d06afc 100644 (file)
@@ -88,6 +88,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        return traits_type::not_eof(__c);
 
       const __size_type __capacity = _M_string.capacity();
+
+#if _GLIBCXX_USE_CXX11_ABI
+      if ((this->epptr() - this->pbase()) < __capacity)
+       {
+         // There is additional capacity in _M_string that can be used.
+         char_type* __base = const_cast<char_type*>(_M_string.data());
+         _M_pbump(__base, __base + __capacity, this->pptr() - this->pbase());
+         if (_M_mode & ios_base::in)
+           {
+             const __size_type __nget = this->gptr() - this->eback();
+             const __size_type __eget = this->egptr() - this->eback();
+             this->setg(__base, __base + __nget, __base + __eget + 1);
+           }
+         *this->pptr() = traits_type::to_char_type(__c);
+         this->pbump(1);
+         return __c;
+       }
+#endif
+
       const __size_type __max_size = _M_string.max_size();
       const bool __testput = this->pptr() < this->epptr();
       if (__builtin_expect(!__testput && __capacity == __max_size, false))
index 2a56d7348066395c9440acda9895c48afb8ccd61..7690252b3e320e87c5e1ae21baa4cd90ac4dfdcc 100644 (file)
@@ -302,18 +302,31 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
        __xfer_bufptrs(const basic_stringbuf& __from, basic_stringbuf* __to)
        : _M_to{__to}, _M_goff{-1, -1, -1}, _M_poff{-1, -1, -1}
        {
-         const _CharT* __str = __from._M_string.data();
+         const _CharT* const __str = __from._M_string.data();
+         const _CharT* __end = nullptr;
          if (__from.eback())
            {
-           _M_goff[0] = __from.eback() - __str;
-           _M_goff[1] = __from.gptr() - __str;
-           _M_goff[2] = __from.egptr() - __str;
+             _M_goff[0] = __from.eback() - __str;
+             _M_goff[1] = __from.gptr() - __str;
+             _M_goff[2] = __from.egptr() - __str;
+             __end = __from.egptr();
            }
          if (__from.pbase())
            {
              _M_poff[0] = __from.pbase() - __str;
              _M_poff[1] = __from.pptr() - __from.pbase();
              _M_poff[2] = __from.epptr() - __str;
+             if (__from.pptr() > __end)
+               __end = __from.pptr();
+           }
+
+         // Set _M_string length to the greater of the get and put areas.
+         if (__end)
+           {
+             // The const_cast avoids changing this constructor's signature,
+             // because it is exported from the dynamic library.
+             auto& __mut_from = const_cast<basic_stringbuf&>(__from);
+             __mut_from._M_string._M_length(__end - __str);
            }
        }
 
diff --git a/libstdc++-v3/testsuite/27_io/basic_stringstream/assign/81338.cc b/libstdc++-v3/testsuite/27_io/basic_stringstream/assign/81338.cc
new file mode 100644 (file)
index 0000000..30370c0
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+#include <sstream>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  std::stringstream ss;
+  for (int i = 0; i < 100; ++i)
+  {
+    ss << 'a';
+    VERIFY( static_cast<bool>(ss) );
+    VERIFY( ss.str() == "a" );
+    ss = std::stringstream();
+  }
+}
+
+int
+main()
+{
+  test01();
+}