From 93ef155b3d2b4de31dec16596f71f3c1eb9b8a03 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Mon, 10 Jul 2017 18:58:56 +0100 Subject: [PATCH] PR libstdc++/81338 correctly manage string capacity 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 | 11 +++++ libstdc++-v3/include/bits/basic_string.h | 5 ++- libstdc++-v3/include/bits/sstream.tcc | 19 +++++++++ libstdc++-v3/include/std/sstream | 21 ++++++++-- .../27_io/basic_stringstream/assign/81338.cc | 40 +++++++++++++++++++ 5 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 libstdc++-v3/testsuite/27_io/basic_stringstream/assign/81338.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 20d80202ad7..58adb85608b 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,14 @@ +2017-07-10 Jonathan Wakely + + 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 * testsuite/20_util/specialized_algorithms/memory_management_tools/ diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index 519d686063e..7fd867c6acc 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -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 friend class basic_stringbuf; + }; _GLIBCXX_END_NAMESPACE_CXX11 #else // !_GLIBCXX_USE_CXX11_ABI // Reference-counted COW string implentation diff --git a/libstdc++-v3/include/bits/sstream.tcc b/libstdc++-v3/include/bits/sstream.tcc index 72e8742b4cf..fc2fcb8992d 100644 --- a/libstdc++-v3/include/bits/sstream.tcc +++ b/libstdc++-v3/include/bits/sstream.tcc @@ -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(_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)) diff --git a/libstdc++-v3/include/std/sstream b/libstdc++-v3/include/std/sstream index 2a56d734806..7690252b3e3 100644 --- a/libstdc++-v3/include/std/sstream +++ b/libstdc++-v3/include/std/sstream @@ -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(__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 index 00000000000..30370c0dd42 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_stringstream/assign/81338.cc @@ -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 +// . + +// { dg-do run { target c++11 } } + +#include +#include + +void +test01() +{ + std::stringstream ss; + for (int i = 0; i < 100; ++i) + { + ss << 'a'; + VERIFY( static_cast(ss) ); + VERIFY( ss.str() == "a" ); + ss = std::stringstream(); + } +} + +int +main() +{ + test01(); +} -- 2.30.2