From f4903afd9351ebc089c694834faa52ec4fcd1d8a Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Mon, 9 Mar 2015 17:08:51 +0000 Subject: [PATCH] Fix an exception-safety bug in . Reference: PR#22650. Not closing the bug because there's more work to do here llvm-svn: 231672 --- libcxx/include/deque | 42 +++++++++------------- .../push_back_exception_safety.pass.cpp | 22 +++++++++++- .../push_front_exception_safety.pass.cpp | 20 +++++++++++ 3 files changed, 57 insertions(+), 27 deletions(-) diff --git a/libcxx/include/deque b/libcxx/include/deque index 6b419c5..8d0d2a8 100644 --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -2288,19 +2288,14 @@ deque<_Tp, _Allocator>::__add_front_capacity() __split_buffer __buf(max(2 * __base::__map_.capacity(), 1), 0, __base::__map_.__alloc()); -#ifndef _LIBCPP_NO_EXCEPTIONS - try - { -#endif // _LIBCPP_NO_EXCEPTIONS - __buf.push_back(__alloc_traits::allocate(__a, __base::__block_size)); -#ifndef _LIBCPP_NO_EXCEPTIONS - } - catch (...) - { - __alloc_traits::deallocate(__a, __buf.front(), __base::__block_size); - throw; - } -#endif // _LIBCPP_NO_EXCEPTIONS + + typedef __allocator_destructor<_Allocator> _Dp; + unique_ptr __hold( + __alloc_traits::allocate(__a, __base::__block_size), + _Dp(__a, __base::__block_size)); + __buf.push_back(__hold.get()); + __hold.release(); + for (typename __base::__map_pointer __i = __base::__map_.begin(); __i != __base::__map_.end(); ++__i) __buf.push_back(*__i); @@ -2436,19 +2431,14 @@ deque<_Tp, _Allocator>::__add_back_capacity() __buf(max(2* __base::__map_.capacity(), 1), __base::__map_.size(), __base::__map_.__alloc()); -#ifndef _LIBCPP_NO_EXCEPTIONS - try - { -#endif // _LIBCPP_NO_EXCEPTIONS - __buf.push_back(__alloc_traits::allocate(__a, __base::__block_size)); -#ifndef _LIBCPP_NO_EXCEPTIONS - } - catch (...) - { - __alloc_traits::deallocate(__a, __buf.back(), __base::__block_size); - throw; - } -#endif // _LIBCPP_NO_EXCEPTIONS + + typedef __allocator_destructor<_Allocator> _Dp; + unique_ptr __hold( + __alloc_traits::allocate(__a, __base::__block_size), + _Dp(__a, __base::__block_size)); + __buf.push_back(__hold.get()); + __hold.release(); + for (typename __base::__map_pointer __i = __base::__map_.end(); __i != __base::__map_.begin();) __buf.push_front(*--__i); diff --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp index 3e62879..8ad6b53 100644 --- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp +++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp @@ -12,12 +12,12 @@ // void push_back(const value_type& x); #include +#include "test_allocator.h" #include // Flag that makes the copy constructor for CMyClass throw an exception static bool gCopyConstructorShouldThow = false; - class CMyClass { public: CMyClass(int tag); public: CMyClass(const CMyClass& iOther); @@ -25,6 +25,7 @@ class CMyClass { bool equal(const CMyClass &rhs) const { return fTag == rhs.fTag && fMagicValue == rhs.fMagicValue; } + private: int fMagicValue; int fTag; @@ -66,6 +67,7 @@ bool operator==(const CMyClass &lhs, const CMyClass &rhs) { return lhs.equal(rhs int main() { CMyClass instance(42); + { std::deque vec; vec.push_back(instance); @@ -74,8 +76,26 @@ int main() gCopyConstructorShouldThow = true; try { vec.push_back(instance); + assert(false); + } + catch (...) { + gCopyConstructorShouldThow = false; + assert(vec==vec2); + } + } + + { + typedef std::deque > C; + C vec; + C vec2(vec); + + C::allocator_type::throw_after = 1; + try { + vec.push_back(instance); + assert(false); } catch (...) { assert(vec==vec2); } + } } diff --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp index 6ae06db..e01b2a2 100644 --- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp +++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp @@ -13,6 +13,7 @@ #include #include +#include "test_allocator.h" // Flag that makes the copy constructor for CMyClass throw an exception static bool gCopyConstructorShouldThow = false; @@ -66,6 +67,7 @@ bool operator==(const CMyClass &lhs, const CMyClass &rhs) { return lhs.equal(rhs int main() { CMyClass instance(42); + { std::deque vec; vec.push_front(instance); @@ -74,8 +76,26 @@ int main() gCopyConstructorShouldThow = true; try { vec.push_front(instance); + assert(false); } catch (...) { + gCopyConstructorShouldThow = false; assert(vec==vec2); } + } + + { + typedef std::deque > C; + C vec; + C vec2(vec); + + C::allocator_type::throw_after = 1; + try { + vec.push_front(instance); + assert(false); + } + catch (...) { + assert(vec==vec2); + } + } } -- 2.7.4