From: Jonathan Wakely Date: Mon, 4 Sep 2017 16:41:25 +0000 (+0100) Subject: PR libstdc++/81338 correctly manage string capacity X-Git-Tag: releases/gcc-5.5.0~87 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6d0de8ed95799afd1d463e3b0015462ec9f9d9fc;p=thirdparty%2Fgcc.git PR libstdc++/81338 correctly manage string capacity Backport from mainline 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. From-SVN: r251669 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 7f4febaade6f..2e3b06351921 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,17 @@ +2017-09-04 Jonathan Wakely + + Backport from mainline + 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-09-01 Jonathan Wakely Backport from mainline diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index de56d86fd83b..cccf6765695b 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -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 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 67c27f79181f..365c61f9448a 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 aa4a71aa5acd..fe67d3d4a605 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 000000000000..3c6c54b4d0c2 --- /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-options "-std=gnu++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(); +}