mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-21 17:21:03 +08:00
re PR libstdc++/78389 (list::merge and list::sort are not exception safe)
PR libstdc++/78389 * include/bits/list.tcc (merge(list&&)): Adjust list sizes if the comparator throws. (merge(list&&, _StrictWeakOrdering)): Likewise. (sort()): Splice elements back from the scratch buffers if the comparator throws. (sort(_StrictWeakOrdering)): Likewise. * testsuite/23_containers/list/operations/78389.cc: New. From-SVN: r244439
This commit is contained in:
parent
45cac8baeb
commit
e5dcfacf43
@ -1,3 +1,14 @@
|
||||
2017-01-13 Ville Voutilainen <ville.voutilainen@gmail.com>
|
||||
|
||||
PR libstdc++/78389
|
||||
* include/bits/list.tcc (merge(list&&)):
|
||||
Adjust list sizes if the comparator throws.
|
||||
(merge(list&&, _StrictWeakOrdering)): Likewise.
|
||||
(sort()): Splice elements back from the scratch buffers
|
||||
if the comparator throws.
|
||||
(sort(_StrictWeakOrdering)): Likewise.
|
||||
* testsuite/23_containers/list/operations/78389.cc: New.
|
||||
|
||||
2017-01-13 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
* testsuite/23_containers/unordered_set/allocator/ext_ptr.cc: Mark
|
||||
|
@ -380,26 +380,36 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
|
||||
// 300. list::merge() specification incomplete
|
||||
if (this != std::__addressof(__x))
|
||||
{
|
||||
_M_check_equal_allocators(__x);
|
||||
_M_check_equal_allocators(__x);
|
||||
|
||||
iterator __first1 = begin();
|
||||
iterator __last1 = end();
|
||||
iterator __first2 = __x.begin();
|
||||
iterator __last2 = __x.end();
|
||||
while (__first1 != __last1 && __first2 != __last2)
|
||||
if (*__first2 < *__first1)
|
||||
{
|
||||
iterator __next = __first2;
|
||||
_M_transfer(__first1, __first2, ++__next);
|
||||
__first2 = __next;
|
||||
}
|
||||
else
|
||||
++__first1;
|
||||
if (__first2 != __last2)
|
||||
_M_transfer(__last1, __first2, __last2);
|
||||
const size_t __orig_size = __x.size();
|
||||
__try {
|
||||
while (__first1 != __last1 && __first2 != __last2)
|
||||
if (*__first2 < *__first1)
|
||||
{
|
||||
iterator __next = __first2;
|
||||
_M_transfer(__first1, __first2, ++__next);
|
||||
__first2 = __next;
|
||||
}
|
||||
else
|
||||
++__first1;
|
||||
if (__first2 != __last2)
|
||||
_M_transfer(__last1, __first2, __last2);
|
||||
|
||||
this->_M_inc_size(__x._M_get_size());
|
||||
__x._M_set_size(0);
|
||||
this->_M_inc_size(__x._M_get_size());
|
||||
__x._M_set_size(0);
|
||||
}
|
||||
__catch(...)
|
||||
{
|
||||
size_t __dist = std::distance(__first2, __last2);
|
||||
this->_M_inc_size(__dist);
|
||||
__x._M_set_size(__orig_size - __dist);
|
||||
__throw_exception_again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -423,20 +433,31 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
|
||||
iterator __last1 = end();
|
||||
iterator __first2 = __x.begin();
|
||||
iterator __last2 = __x.end();
|
||||
while (__first1 != __last1 && __first2 != __last2)
|
||||
if (__comp(*__first2, *__first1))
|
||||
{
|
||||
iterator __next = __first2;
|
||||
_M_transfer(__first1, __first2, ++__next);
|
||||
__first2 = __next;
|
||||
}
|
||||
else
|
||||
++__first1;
|
||||
if (__first2 != __last2)
|
||||
_M_transfer(__last1, __first2, __last2);
|
||||
const size_t __orig_size = __x.size();
|
||||
__try
|
||||
{
|
||||
while (__first1 != __last1 && __first2 != __last2)
|
||||
if (__comp(*__first2, *__first1))
|
||||
{
|
||||
iterator __next = __first2;
|
||||
_M_transfer(__first1, __first2, ++__next);
|
||||
__first2 = __next;
|
||||
}
|
||||
else
|
||||
++__first1;
|
||||
if (__first2 != __last2)
|
||||
_M_transfer(__last1, __first2, __last2);
|
||||
|
||||
this->_M_inc_size(__x._M_get_size());
|
||||
__x._M_set_size(0);
|
||||
this->_M_inc_size(__x._M_get_size());
|
||||
__x._M_set_size(0);
|
||||
}
|
||||
__catch(...)
|
||||
{
|
||||
size_t __dist = std::distance(__first2, __last2);
|
||||
this->_M_inc_size(__dist);
|
||||
__x._M_set_size(__orig_size - __dist);
|
||||
__throw_exception_again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -453,27 +474,36 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
|
||||
list __tmp[64];
|
||||
list * __fill = __tmp;
|
||||
list * __counter;
|
||||
|
||||
do
|
||||
__try
|
||||
{
|
||||
__carry.splice(__carry.begin(), *this, begin());
|
||||
|
||||
for(__counter = __tmp;
|
||||
__counter != __fill && !__counter->empty();
|
||||
++__counter)
|
||||
do
|
||||
{
|
||||
__counter->merge(__carry);
|
||||
__carry.swap(*__counter);
|
||||
}
|
||||
__carry.swap(*__counter);
|
||||
if (__counter == __fill)
|
||||
++__fill;
|
||||
}
|
||||
while ( !empty() );
|
||||
__carry.splice(__carry.begin(), *this, begin());
|
||||
|
||||
for (__counter = __tmp + 1; __counter != __fill; ++__counter)
|
||||
__counter->merge(*(__counter - 1));
|
||||
swap( *(__fill - 1) );
|
||||
for(__counter = __tmp;
|
||||
__counter != __fill && !__counter->empty();
|
||||
++__counter)
|
||||
{
|
||||
__counter->merge(__carry);
|
||||
__carry.swap(*__counter);
|
||||
}
|
||||
__carry.swap(*__counter);
|
||||
if (__counter == __fill)
|
||||
++__fill;
|
||||
}
|
||||
while ( !empty() );
|
||||
|
||||
for (__counter = __tmp + 1; __counter != __fill; ++__counter)
|
||||
__counter->merge(*(__counter - 1));
|
||||
swap( *(__fill - 1) );
|
||||
}
|
||||
__catch(...)
|
||||
{
|
||||
this->splice(this->end(), __carry);
|
||||
for (int i = 0; i < sizeof(__tmp)/sizeof(__tmp[0]); ++i)
|
||||
this->splice(this->end(), __tmp[i]);
|
||||
__throw_exception_again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -530,27 +560,36 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
|
||||
list __tmp[64];
|
||||
list * __fill = __tmp;
|
||||
list * __counter;
|
||||
|
||||
do
|
||||
__try
|
||||
{
|
||||
__carry.splice(__carry.begin(), *this, begin());
|
||||
|
||||
for(__counter = __tmp;
|
||||
__counter != __fill && !__counter->empty();
|
||||
++__counter)
|
||||
do
|
||||
{
|
||||
__counter->merge(__carry, __comp);
|
||||
__carry.swap(*__counter);
|
||||
}
|
||||
__carry.swap(*__counter);
|
||||
if (__counter == __fill)
|
||||
++__fill;
|
||||
}
|
||||
while ( !empty() );
|
||||
__carry.splice(__carry.begin(), *this, begin());
|
||||
|
||||
for (__counter = __tmp + 1; __counter != __fill; ++__counter)
|
||||
__counter->merge(*(__counter - 1), __comp);
|
||||
swap(*(__fill - 1));
|
||||
for(__counter = __tmp;
|
||||
__counter != __fill && !__counter->empty();
|
||||
++__counter)
|
||||
{
|
||||
__counter->merge(__carry, __comp);
|
||||
__carry.swap(*__counter);
|
||||
}
|
||||
__carry.swap(*__counter);
|
||||
if (__counter == __fill)
|
||||
++__fill;
|
||||
}
|
||||
while ( !empty() );
|
||||
|
||||
for (__counter = __tmp + 1; __counter != __fill; ++__counter)
|
||||
__counter->merge(*(__counter - 1), __comp);
|
||||
swap(*(__fill - 1));
|
||||
}
|
||||
__catch(...)
|
||||
{
|
||||
this->splice(this->end(), __carry);
|
||||
for (int i = 0; i < sizeof(__tmp)/sizeof(__tmp[0]); ++i)
|
||||
this->splice(this->end(), __tmp[i]);
|
||||
__throw_exception_again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,85 @@
|
||||
// { dg-do run { target c++11 } }
|
||||
|
||||
// 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/>.
|
||||
|
||||
// 23.2.2.4 list operations [lib.list.ops]
|
||||
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
struct ThrowingComparator
|
||||
{
|
||||
unsigned int throw_after = 0;
|
||||
unsigned int count = 0;
|
||||
bool operator()(int, int) {
|
||||
if (++count >= throw_after) {
|
||||
throw 666;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct X
|
||||
{
|
||||
X() = default;
|
||||
X(int) {}
|
||||
};
|
||||
|
||||
unsigned int throw_after_X = 0;
|
||||
unsigned int count_X = 0;
|
||||
|
||||
bool operator<(const X&, const X&) {
|
||||
if (++count_X >= throw_after_X) {
|
||||
throw 666;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
std::list<int> a{1, 2, 3, 4};
|
||||
std::list<int> b{5, 6, 7, 8, 9, 10, 11, 12};
|
||||
try {
|
||||
a.merge(b, ThrowingComparator{5});
|
||||
} catch (...) {
|
||||
}
|
||||
VERIFY(a.size() == 8 && b.size() == 4);
|
||||
std::list<X> ax{1, 2, 3, 4};
|
||||
std::list<X> bx{5, 6, 7, 8, 9, 10, 11, 12};
|
||||
throw_after_X = 5;
|
||||
try {
|
||||
ax.merge(bx);
|
||||
} catch (...) {
|
||||
}
|
||||
VERIFY(ax.size() == 8 && bx.size() == 4);
|
||||
std::list<int> ay{5, 6, 7, 8, 9, 10, 11, 12};
|
||||
try {
|
||||
ay.sort(ThrowingComparator{5});
|
||||
} catch (...) {
|
||||
}
|
||||
VERIFY(ay.size() == 8);
|
||||
std::list<X> az{5, 6, 7, 8, 9, 10, 11, 12};
|
||||
throw_after_X = 5;
|
||||
try {
|
||||
az.sort();
|
||||
} catch (...) {
|
||||
}
|
||||
VERIFY(az.size() == 8);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user