Fix an exception-safety bug in <deque>. Reference: PR#22650. Not closing the bug because there's more work to do here
git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@231672 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
2020d8ac89
commit
d07fcd66b9
@ -2288,19 +2288,14 @@ deque<_Tp, _Allocator>::__add_front_capacity()
|
|||||||
__split_buffer<pointer, typename __base::__pointer_allocator&>
|
__split_buffer<pointer, typename __base::__pointer_allocator&>
|
||||||
__buf(max<size_type>(2 * __base::__map_.capacity(), 1),
|
__buf(max<size_type>(2 * __base::__map_.capacity(), 1),
|
||||||
0, __base::__map_.__alloc());
|
0, __base::__map_.__alloc());
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
|
||||||
try
|
typedef __allocator_destructor<_Allocator> _Dp;
|
||||||
{
|
unique_ptr<pointer, _Dp> __hold(
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
__alloc_traits::allocate(__a, __base::__block_size),
|
||||||
__buf.push_back(__alloc_traits::allocate(__a, __base::__block_size));
|
_Dp(__a, __base::__block_size));
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
__buf.push_back(__hold.get());
|
||||||
}
|
__hold.release();
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
__alloc_traits::deallocate(__a, __buf.front(), __base::__block_size);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
|
||||||
for (typename __base::__map_pointer __i = __base::__map_.begin();
|
for (typename __base::__map_pointer __i = __base::__map_.begin();
|
||||||
__i != __base::__map_.end(); ++__i)
|
__i != __base::__map_.end(); ++__i)
|
||||||
__buf.push_back(*__i);
|
__buf.push_back(*__i);
|
||||||
@ -2436,19 +2431,14 @@ deque<_Tp, _Allocator>::__add_back_capacity()
|
|||||||
__buf(max<size_type>(2* __base::__map_.capacity(), 1),
|
__buf(max<size_type>(2* __base::__map_.capacity(), 1),
|
||||||
__base::__map_.size(),
|
__base::__map_.size(),
|
||||||
__base::__map_.__alloc());
|
__base::__map_.__alloc());
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
|
||||||
try
|
typedef __allocator_destructor<_Allocator> _Dp;
|
||||||
{
|
unique_ptr<pointer, _Dp> __hold(
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
__alloc_traits::allocate(__a, __base::__block_size),
|
||||||
__buf.push_back(__alloc_traits::allocate(__a, __base::__block_size));
|
_Dp(__a, __base::__block_size));
|
||||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
__buf.push_back(__hold.get());
|
||||||
}
|
__hold.release();
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
__alloc_traits::deallocate(__a, __buf.back(), __base::__block_size);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
#endif // _LIBCPP_NO_EXCEPTIONS
|
|
||||||
for (typename __base::__map_pointer __i = __base::__map_.end();
|
for (typename __base::__map_pointer __i = __base::__map_.end();
|
||||||
__i != __base::__map_.begin();)
|
__i != __base::__map_.begin();)
|
||||||
__buf.push_front(*--__i);
|
__buf.push_front(*--__i);
|
||||||
|
@ -12,12 +12,12 @@
|
|||||||
// void push_back(const value_type& x);
|
// void push_back(const value_type& x);
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include "test_allocator.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
// Flag that makes the copy constructor for CMyClass throw an exception
|
// Flag that makes the copy constructor for CMyClass throw an exception
|
||||||
static bool gCopyConstructorShouldThow = false;
|
static bool gCopyConstructorShouldThow = false;
|
||||||
|
|
||||||
|
|
||||||
class CMyClass {
|
class CMyClass {
|
||||||
public: CMyClass(int tag);
|
public: CMyClass(int tag);
|
||||||
public: CMyClass(const CMyClass& iOther);
|
public: CMyClass(const CMyClass& iOther);
|
||||||
@ -25,6 +25,7 @@ class CMyClass {
|
|||||||
|
|
||||||
bool equal(const CMyClass &rhs) const
|
bool equal(const CMyClass &rhs) const
|
||||||
{ return fTag == rhs.fTag && fMagicValue == rhs.fMagicValue; }
|
{ return fTag == rhs.fTag && fMagicValue == rhs.fMagicValue; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int fMagicValue;
|
int fMagicValue;
|
||||||
int fTag;
|
int fTag;
|
||||||
@ -66,6 +67,7 @@ bool operator==(const CMyClass &lhs, const CMyClass &rhs) { return lhs.equal(rhs
|
|||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
CMyClass instance(42);
|
CMyClass instance(42);
|
||||||
|
{
|
||||||
std::deque<CMyClass> vec;
|
std::deque<CMyClass> vec;
|
||||||
|
|
||||||
vec.push_back(instance);
|
vec.push_back(instance);
|
||||||
@ -74,8 +76,26 @@ int main()
|
|||||||
gCopyConstructorShouldThow = true;
|
gCopyConstructorShouldThow = true;
|
||||||
try {
|
try {
|
||||||
vec.push_back(instance);
|
vec.push_back(instance);
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
gCopyConstructorShouldThow = false;
|
||||||
|
assert(vec==vec2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
typedef std::deque<CMyClass, test_allocator<CMyClass> > C;
|
||||||
|
C vec;
|
||||||
|
C vec2(vec);
|
||||||
|
|
||||||
|
C::allocator_type::throw_after = 1;
|
||||||
|
try {
|
||||||
|
vec.push_back(instance);
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
assert(vec==vec2);
|
assert(vec==vec2);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include "test_allocator.h"
|
||||||
|
|
||||||
// Flag that makes the copy constructor for CMyClass throw an exception
|
// Flag that makes the copy constructor for CMyClass throw an exception
|
||||||
static bool gCopyConstructorShouldThow = false;
|
static bool gCopyConstructorShouldThow = false;
|
||||||
@ -66,6 +67,7 @@ bool operator==(const CMyClass &lhs, const CMyClass &rhs) { return lhs.equal(rhs
|
|||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
CMyClass instance(42);
|
CMyClass instance(42);
|
||||||
|
{
|
||||||
std::deque<CMyClass> vec;
|
std::deque<CMyClass> vec;
|
||||||
|
|
||||||
vec.push_front(instance);
|
vec.push_front(instance);
|
||||||
@ -74,8 +76,26 @@ int main()
|
|||||||
gCopyConstructorShouldThow = true;
|
gCopyConstructorShouldThow = true;
|
||||||
try {
|
try {
|
||||||
vec.push_front(instance);
|
vec.push_front(instance);
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
gCopyConstructorShouldThow = false;
|
||||||
|
assert(vec==vec2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
typedef std::deque<CMyClass, test_allocator<CMyClass> > C;
|
||||||
|
C vec;
|
||||||
|
C vec2(vec);
|
||||||
|
|
||||||
|
C::allocator_type::throw_after = 1;
|
||||||
|
try {
|
||||||
|
vec.push_front(instance);
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
assert(vec==vec2);
|
assert(vec==vec2);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user