From: Daniel Trebbien Date: Thu, 14 Jun 2018 09:26:51 +0000 (+0000) Subject: PR libstdc++/83982 fix exception-safety guarantee of std::vector::resize X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=4c1d999a7e937da0d417e8153f54b646603bb210;p=gcc.git PR libstdc++/83982 fix exception-safety guarantee of std::vector::resize Construct new elements before moving existing ones, so that if a default constructor throws, the existing elements are not left in a moved-from state. 2018-06-14 Daniel Trebbien Jonathan Wakely PR libstdc++/83982 * include/bits/vector.tcc (vector::_M_default_append(size_type)): Default-construct new elements before moving existing ones. * testsuite/23_containers/vector/capacity/resize/strong_guarantee.cc: New. Co-Authored-By: Jonathan Wakely From-SVN: r261585 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 223b32732dd..923841ab2c7 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,12 @@ +2018-06-14 Daniel Trebbien + Jonathan Wakely + + PR libstdc++/83982 + * include/bits/vector.tcc (vector::_M_default_append(size_type)): + Default-construct new elements before moving existing ones. + * testsuite/23_containers/vector/capacity/resize/strong_guarantee.cc: + New. + 2018-06-13 Jonathan Wakely PR libstdc++/86127 diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc index 1d1ef427b26..86a711713b2 100644 --- a/libstdc++-v3/include/bits/vector.tcc +++ b/libstdc++-v3/include/bits/vector.tcc @@ -582,7 +582,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { if (__n != 0) { - size_type __size = size(); + const size_type __size = size(); size_type __navail = size_type(this->_M_impl._M_end_of_storage - this->_M_impl._M_finish); @@ -601,23 +601,22 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { const size_type __len = _M_check_len(__n, "vector::_M_default_append"); - const size_type __old_size = __size; pointer __new_start(this->_M_allocate(__len)); - pointer __new_finish(__new_start); + pointer __destroy_from = pointer(); __try { - __new_finish - = std::__uninitialized_move_if_noexcept_a - (this->_M_impl._M_start, this->_M_impl._M_finish, - __new_start, _M_get_Tp_allocator()); - __new_finish = - std::__uninitialized_default_n_a(__new_finish, __n, - _M_get_Tp_allocator()); + std::__uninitialized_default_n_a(__new_start + __size, + __n, _M_get_Tp_allocator()); + __destroy_from = __new_start + __size; + std::__uninitialized_move_if_noexcept_a( + this->_M_impl._M_start, this->_M_impl._M_finish, + __new_start, _M_get_Tp_allocator()); } __catch(...) { - std::_Destroy(__new_start, __new_finish, - _M_get_Tp_allocator()); + if (__destroy_from) + std::_Destroy(__destroy_from, __destroy_from + __n, + _M_get_Tp_allocator()); _M_deallocate(__new_start, __len); __throw_exception_again; } @@ -628,7 +627,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER this->_M_impl._M_end_of_storage - this->_M_impl._M_start); this->_M_impl._M_start = __new_start; - this->_M_impl._M_finish = __new_finish; + this->_M_impl._M_finish = __new_start + __size + __n; this->_M_impl._M_end_of_storage = __new_start + __len; } } diff --git a/libstdc++-v3/testsuite/23_containers/vector/capacity/resize/strong_guarantee.cc b/libstdc++-v3/testsuite/23_containers/vector/capacity/resize/strong_guarantee.cc new file mode 100644 index 00000000000..b209d76867a --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/capacity/resize/strong_guarantee.cc @@ -0,0 +1,60 @@ +// Copyright (C) 2018 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 +// . + +#include +#include + +struct X +{ + X() : data(1) + { + if (fail) + throw 1; + } + + static bool fail; + + std::vector data; +}; + +bool X::fail = false; + +void +test01() +{ + std::vector v(2); + X* const addr = &v[0]; + bool caught = false; + try { + X::fail = true; + v.resize(v.capacity() + 1); // force reallocation + } catch (int) { + caught = true; + } + VERIFY( caught ); + VERIFY( v.size() == 2 ); + VERIFY( &v[0] == addr ); + // PR libstdc++/83982 + VERIFY( ! v[0].data.empty() ); + VERIFY( ! v[1].data.empty() ); +} + +int +main() +{ + test01(); +}