]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR libstdc++/81338 correctly manage string capacity
authorJonathan Wakely <jwakely@redhat.com>
Mon, 4 Sep 2017 16:41:25 +0000 (17:41 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Mon, 4 Sep 2017 16:41:25 +0000 (17:41 +0100)
Backport from mainline
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.

From-SVN: r251669

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 7f4febaade6fecdff01e60d4e5aec3b7d9605848..2e3b063519218cd51e3b045f68624ea93a801cd3 100644 (file)
@@ -1,3 +1,17 @@
+2017-09-04  Jonathan Wakely  <jwakely@redhat.com>
+
+       Backport from mainline
+       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-09-01  Jonathan Wakely  <jwakely@redhat.com>
 
        Backport from mainline
index de56d86fd83b2ef786b6b84237cbff78464a201b..cccf6765695bb736489d932b90fcef0a5624c7a5 100644 (file)
@@ -2529,7 +2529,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 67c27f79181f7171e1cc73a5ef4cb3462fe98381..365c61f9448a9e04e229d53863aa4301aea4f4b3 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 aa4a71aa5acd69832b0490b080277e5a3564e16c..fe67d3d4a605316698059be3001b7132f225d60e 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..3c6c54b
--- /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-options "-std=gnu++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();
+}