From 32917686b0ebb596fe0d783328a771c4dfd759ef Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 16 Aug 2016 12:33:16 +0100 Subject: [PATCH] PR 72847 Prevent double-free in std::vector PR libstdc++/72847 * include/bits/stl_bvector.h (_Bvector_base::_M_deallocate): Zero pointers to start and end of storage. * testsuite/23_containers/vector/bool/72847.cc: New test. * include/bits/vector.tcc (vector::_M_reallocate): Only update _M_finish after deallocating. (vector::_M_fill_insert): Likewise. (vector::_M_insert_range): Likewise. (vector::_M_insert_aux): Likewise. From-SVN: r239497 --- libstdc++-v3/ChangeLog | 12 +++++ libstdc++-v3/include/bits/stl_bvector.h | 2 + libstdc++-v3/include/bits/vector.tcc | 14 ++++-- .../23_containers/vector/bool/72847.cc | 49 +++++++++++++++++++ 4 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 libstdc++-v3/testsuite/23_containers/vector/bool/72847.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 73ddaac385d..a7689f451f5 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,15 @@ +2016-08-16 Jonathan Wakely + + PR libstdc++/72847 + * include/bits/stl_bvector.h (_Bvector_base::_M_deallocate): Zero + pointers to start and end of storage. + * testsuite/23_containers/vector/bool/72847.cc: New test. + * include/bits/vector.tcc (vector::_M_reallocate): Only update + _M_finish after deallocating. + (vector::_M_fill_insert): Likewise. + (vector::_M_insert_range): Likewise. + (vector::_M_insert_aux): Likewise. + 2016-08-15 Ville Voutilainen Implement LWG 2744 and LWG 2754. diff --git a/libstdc++-v3/include/bits/stl_bvector.h b/libstdc++-v3/include/bits/stl_bvector.h index 629fe4dd902..b3ac63f521f 100644 --- a/libstdc++-v3/include/bits/stl_bvector.h +++ b/libstdc++-v3/include/bits/stl_bvector.h @@ -500,6 +500,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _Bit_alloc_traits::deallocate(_M_impl, _M_impl._M_end_of_storage - __n, __n); + _M_impl._M_start = _M_impl._M_finish = _Bit_iterator(); + _M_impl._M_end_of_storage = _Bit_pointer(); } } diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc index 9717b74a978..6926a8b91c4 100644 --- a/libstdc++-v3/include/bits/vector.tcc +++ b/libstdc++-v3/include/bits/vector.tcc @@ -708,9 +708,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { _Bit_pointer __q = this->_M_allocate(__n); iterator __start(std::__addressof(*__q), 0); - this->_M_impl._M_finish = _M_copy_aligned(begin(), end(), __start); + iterator __finish(_M_copy_aligned(begin(), end(), __start)); this->_M_deallocate(); this->_M_impl._M_start = __start; + this->_M_impl._M_finish = __finish; this->_M_impl._M_end_of_storage = __q + _S_nword(__n); } @@ -736,11 +737,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER iterator __start(std::__addressof(*__q), 0); iterator __i = _M_copy_aligned(begin(), __position, __start); std::fill(__i, __i + difference_type(__n), __x); - this->_M_impl._M_finish = std::copy(__position, end(), - __i + difference_type(__n)); + iterator __finish = std::copy(__position, end(), + __i + difference_type(__n)); this->_M_deallocate(); this->_M_impl._M_end_of_storage = __q + _S_nword(__len); this->_M_impl._M_start = __start; + this->_M_impl._M_finish = __finish; } } @@ -770,10 +772,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER iterator __start(std::__addressof(*__q), 0); iterator __i = _M_copy_aligned(begin(), __position, __start); __i = std::copy(__first, __last, __i); - this->_M_impl._M_finish = std::copy(__position, end(), __i); + iterator __finish = std::copy(__position, end(), __i); this->_M_deallocate(); this->_M_impl._M_end_of_storage = __q + _S_nword(__len); this->_M_impl._M_start = __start; + this->_M_impl._M_finish = __finish; } } } @@ -798,10 +801,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER iterator __start(std::__addressof(*__q), 0); iterator __i = _M_copy_aligned(begin(), __position, __start); *__i++ = __x; - this->_M_impl._M_finish = std::copy(__position, end(), __i); + iterator __finish = std::copy(__position, end(), __i); this->_M_deallocate(); this->_M_impl._M_end_of_storage = __q + _S_nword(__len); this->_M_impl._M_start = __start; + this->_M_impl._M_finish = __finish; } } diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/72847.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/72847.cc new file mode 100644 index 00000000000..7bd8b396efd --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/72847.cc @@ -0,0 +1,49 @@ +// Copyright (C) 2016 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-require-cstdint "" } +// { dg-skip-if "" { *-*-* } { "-fno-exceptions" } } + +#include +#include +#include + +// PR libstdc++/72847 +void +test01() +{ + bool test __attribute((unused)) = true; + + typedef bool value_type; + typedef __gnu_cxx::throw_allocator_limit allocator_type; + typedef std::vector test_type; + test_type v1(1, false); + test_type v2(v1.capacity()+1, false); + allocator_type::set_limit(0); + try { + v1 = v2; + } catch (const __gnu_cxx::forced_error&) { + } + // throw_allocator will throw if double-free happens +} + +// Container requirement testing, exceptional behavior +int main() +{ + test01(); + return 0; +} -- 2.30.2