diff options
author | Ville Voutilainen <ville.voutilainen@gmail.com> | 2016-09-20 18:15:36 +0300 |
---|---|---|
committer | Ville Voutilainen <ville@gcc.gnu.org> | 2016-09-20 18:15:36 +0300 |
commit | 377f30c00f3b8b8b0da748dbb9d988fa67a8ec2f (patch) | |
tree | 356ee8f4d2f55dc7174b1dfcb39e330821546d25 | |
parent | 7d9cf8015969054f044ee815f0308e7130c59b83 (diff) | |
download | gcc-377f30c00f3b8b8b0da748dbb9d988fa67a8ec2f.zip gcc-377f30c00f3b8b8b0da748dbb9d988fa67a8ec2f.tar.gz gcc-377f30c00f3b8b8b0da748dbb9d988fa67a8ec2f.tar.bz2 |
re PR libstdc++/77619 (uninitialized_meow_construct and friends not exception safe)
PR libstdc++/77619
* include/bits/stl_construct.h: (_Construct_novalue): New.
(_Destroy_n_aux, _Destroy_n): New.
* include/bits/stl_uninitialized.h: (type_traits):
New include in C++11 mode.
(__uninitialized_default_novalue_1): New.
(__uninitialized_default_novalue_n_1): Likewise.
(__uninitialized_default_novalue): Likewise.
(__uninitialized_default_novalue_n): Likewise.
(__uninitialized_copy_n_pair): Likewise.
(uninitialized_default_construct):
Use __uninitialized_default_novalue.
(uninitialized_default_construct_n):
Use __uninitialized_default_novalue_n.
(uninitialized_value_construct): Use __uninitialized_default.
(uninitialized_value_construct_n): Use __uninitialized_default_n.
(uninitialized_move): Use uninitialized_copy.
(uninitialized_move_n): Use __uninitialized_copy_n_pair.
(destroy_at): Use _Destroy.
(destroy): Likewise.
(destroy_n): Likewise.
* testsuite/20_util/specialized_algorithms/
memory_management_tools/1.cc: Add tests for exceptions,
add tests for trivial cases for construct and move.
From-SVN: r240264
-rw-r--r-- | libstdc++-v3/ChangeLog | 27 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/stl_construct.h | 45 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/stl_uninitialized.h | 185 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/1.cc | 183 |
4 files changed, 410 insertions, 30 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index b50f629..3981509 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,30 @@ +2016-09-20 Ville Voutilainen <ville.voutilainen@gmail.com> + + PR libstdc++/77619 + * include/bits/stl_construct.h: (_Construct_novalue): New. + (_Destroy_n_aux, _Destroy_n): New. + * include/bits/stl_uninitialized.h: (type_traits): + New include in C++11 mode. + (__uninitialized_default_novalue_1): New. + (__uninitialized_default_novalue_n_1): Likewise. + (__uninitialized_default_novalue): Likewise. + (__uninitialized_default_novalue_n): Likewise. + (__uninitialized_copy_n_pair): Likewise. + (uninitialized_default_construct): + Use __uninitialized_default_novalue. + (uninitialized_default_construct_n): + Use __uninitialized_default_novalue_n. + (uninitialized_value_construct): Use __uninitialized_default. + (uninitialized_value_construct_n): Use __uninitialized_default_n. + (uninitialized_move): Use uninitialized_copy. + (uninitialized_move_n): Use __uninitialized_copy_n_pair. + (destroy_at): Use _Destroy. + (destroy): Likewise. + (destroy_n): Likewise. + * testsuite/20_util/specialized_algorithms/ + memory_management_tools/1.cc: Add tests for exceptions, + add tests for trivial cases for construct and move. + 2016-09-20 Jonathan Wakely <jwakely@redhat.com> * python/libstdcxx/v6/xmethods.py (DequeWorkerBase.__init__) diff --git a/libstdc++-v3/include/bits/stl_construct.h b/libstdc++-v3/include/bits/stl_construct.h index 3d12628..4a771c4 100644 --- a/libstdc++-v3/include/bits/stl_construct.h +++ b/libstdc++-v3/include/bits/stl_construct.h @@ -84,6 +84,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif + template<typename _T1> + inline void + _Construct_novalue(_T1* __p) + { ::new(static_cast<void*>(__p)) _T1; } + /** * Destroy the object pointed to by a pointer type. */ @@ -127,6 +132,46 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __destroy(__first, __last); } + template<bool> + struct _Destroy_n_aux + { + template<typename _ForwardIterator, typename _Size> + static _ForwardIterator + __destroy_n(_ForwardIterator __first, _Size __count) + { + for (; __count > 0; (void)++__first, --__count) + std::_Destroy(std::__addressof(*__first)); + return __first; + } + }; + + template<> + struct _Destroy_n_aux<true> + { + template<typename _ForwardIterator, typename _Size> + static _ForwardIterator + __destroy_n(_ForwardIterator __first, _Size __count) + { + std::advance(__first, __count); + return __first; + } + }; + + /** + * Destroy a range of objects. If the value_type of the object has + * a trivial destructor, the compiler should optimize all of this + * away, otherwise the objects' destructors must be invoked. + */ + template<typename _ForwardIterator, typename _Size> + inline _ForwardIterator + _Destroy_n(_ForwardIterator __first, _Size __count) + { + typedef typename iterator_traits<_ForwardIterator>::value_type + _Value_type; + return std::_Destroy_n_aux<__has_trivial_destructor(_Value_type)>:: + __destroy_n(__first, __count); + } + /** * Destroy a range of objects using the supplied allocator. For * nondefault allocators we do not optimize away invocation of diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h index c5c81fb..ef2e584 100644 --- a/libstdc++-v3/include/bits/stl_uninitialized.h +++ b/libstdc++-v3/include/bits/stl_uninitialized.h @@ -60,6 +60,10 @@ #include <utility> #endif +#if __cplusplus >= 201103L +#include <type_traits> +#endif + namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -640,6 +644,100 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION allocator<_Tp>&) { return std::__uninitialized_default_n(__first, __n); } + template<bool _TrivialValueType> + struct __uninitialized_default_novalue_1 + { + template<typename _ForwardIterator> + static void + __uninit_default_novalue(_ForwardIterator __first, + _ForwardIterator __last) + { + _ForwardIterator __cur = __first; + __try + { + for (; __cur != __last; ++__cur) + std::_Construct_novalue(std::__addressof(*__cur)); + } + __catch(...) + { + std::_Destroy(__first, __cur); + __throw_exception_again; + } + } + }; + + template<> + struct __uninitialized_default_novalue_1<true> + { + template<typename _ForwardIterator> + static void + __uninit_default_novalue(_ForwardIterator __first, + _ForwardIterator __last) + { + } + }; + + template<bool _TrivialValueType> + struct __uninitialized_default_novalue_n_1 + { + template<typename _ForwardIterator, typename _Size> + static _ForwardIterator + __uninit_default_novalue_n(_ForwardIterator __first, _Size __n) + { + _ForwardIterator __cur = __first; + __try + { + for (; __n > 0; --__n, ++__cur) + std::_Construct_novalue(std::__addressof(*__cur)); + return __cur; + } + __catch(...) + { + std::_Destroy(__first, __cur); + __throw_exception_again; + } + } + }; + + template<> + struct __uninitialized_default_novalue_n_1<true> + { + template<typename _ForwardIterator, typename _Size> + static _ForwardIterator + __uninit_default_novalue_n(_ForwardIterator __first, _Size __n) + { + } + }; + + // __uninitialized_default_novalue + // Fills [first, last) with std::distance(first, last) default-initialized + // value_types(s). + template<typename _ForwardIterator> + inline void + __uninitialized_default_novalue(_ForwardIterator __first, + _ForwardIterator __last) + { + typedef typename iterator_traits<_ForwardIterator>::value_type + _ValueType; + + std::__uninitialized_default_novalue_1< + is_trivially_default_constructible<_ValueType>::value>:: + __uninit_default_novalue(__first, __last); + } + + // __uninitialized_default_n + // Fills [first, first + n) with n default-initialized value_type(s). + template<typename _ForwardIterator, typename _Size> + inline _ForwardIterator + __uninitialized_default_novalue_n(_ForwardIterator __first, _Size __n) + { + typedef typename iterator_traits<_ForwardIterator>::value_type + _ValueType; + + return __uninitialized_default_novalue_n_1< + is_trivially_default_constructible<_ValueType>::value>:: + __uninit_default_novalue_n(__first, __n); + } template<typename _InputIterator, typename _Size, typename _ForwardIterator> @@ -669,6 +767,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION random_access_iterator_tag) { return std::uninitialized_copy(__first, __first + __n, __result); } + template<typename _InputIterator, typename _Size, + typename _ForwardIterator> + pair<_InputIterator, _ForwardIterator> + __uninitialized_copy_n_pair(_InputIterator __first, _Size __n, + _ForwardIterator __result, input_iterator_tag) + { + _ForwardIterator __cur = __result; + __try + { + for (; __n > 0; --__n, ++__first, ++__cur) + std::_Construct(std::__addressof(*__cur), *__first); + return {__first, __cur}; + } + __catch(...) + { + std::_Destroy(__result, __cur); + __throw_exception_again; + } + } + + template<typename _RandomAccessIterator, typename _Size, + typename _ForwardIterator> + inline pair<_RandomAccessIterator, _ForwardIterator> + __uninitialized_copy_n_pair(_RandomAccessIterator __first, _Size __n, + _ForwardIterator __result, + random_access_iterator_tag) + { + auto __second_res = uninitialized_copy(__first, __first + __n, __result); + auto __first_res = std::next(__first, __n); + return {__first_res, __second_res}; + } + /** * @brief Copies the range [first,first+n) into result. * @param __first An input iterator. @@ -684,6 +814,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _ForwardIterator __result) { return std::__uninitialized_copy_n(__first, __n, __result, std::__iterator_category(__first)); } + + template<typename _InputIterator, typename _Size, typename _ForwardIterator> + inline pair<_InputIterator, _ForwardIterator> + __uninitialized_copy_n_pair(_InputIterator __first, _Size __n, + _ForwardIterator __result) + { + return + std::__uninitialized_copy_n_pair(__first, __n, __result, + std::__iterator_category(__first)); + } + #endif #if __cplusplus > 201402L @@ -692,19 +833,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION uninitialized_default_construct(_ForwardIterator __first, _ForwardIterator __last) { - for (; __first != __last; ++__first) - ::new (static_cast<void*>(std::__addressof(*__first))) - typename iterator_traits<_ForwardIterator>::value_type; + __uninitialized_default_novalue(__first, __last); } template <typename _ForwardIterator, typename _Size> inline _ForwardIterator uninitialized_default_construct_n(_ForwardIterator __first, _Size __count) { - for (; __count > 0; (void)++__first, --__count) - ::new (static_cast<void*>(std::__addressof(*__first))) - typename iterator_traits<_ForwardIterator>::value_type; - return __first; + return __uninitialized_default_novalue_n(__first, __count); } template <typename _ForwardIterator> @@ -712,19 +848,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION uninitialized_value_construct(_ForwardIterator __first, _ForwardIterator __last) { - for (; __first != __last; ++__first) - ::new (static_cast<void*>(std::__addressof(*__first))) - typename iterator_traits<_ForwardIterator>::value_type(); + return __uninitialized_default(__first, __last); } template <typename _ForwardIterator, typename _Size> inline _ForwardIterator uninitialized_value_construct_n(_ForwardIterator __first, _Size __count) { - for (; __count > 0; (void)++__first, --__count) - ::new (static_cast<void*>(std::__addressof(*__first))) - typename iterator_traits<_ForwardIterator>::value_type(); - return __first; + return __uninitialized_default_n(__first, __count); } template <typename _InputIterator, typename _ForwardIterator> @@ -732,11 +863,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION uninitialized_move(_InputIterator __first, _InputIterator __last, _ForwardIterator __result) { - for (; __first != __last; (void)++__result, ++__first) - ::new (static_cast<void*>(std::__addressof(*__result))) - typename - iterator_traits<_ForwardIterator>::value_type(std::move(*__first)); - return __result; + return std::uninitialized_copy + (_GLIBCXX_MAKE_MOVE_ITERATOR(__first), + _GLIBCXX_MAKE_MOVE_ITERATOR(__last), __result); } template <typename _InputIterator, typename _Size, typename _ForwardIterator> @@ -744,35 +873,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION uninitialized_move_n(_InputIterator __first, _Size __count, _ForwardIterator __result) { - for (; __count > 0; ++__result, (void) ++__first, --__count) - ::new (static_cast<void*>(std::__addressof(*__result))) - typename - iterator_traits<_ForwardIterator>::value_type(std::move(*__first)); - return {__first, __result}; + auto __res = std::__uninitialized_copy_n_pair + (_GLIBCXX_MAKE_MOVE_ITERATOR(__first), + __count, __result); + return {__res.first.base(), __res.second}; } template <typename _Tp> inline void destroy_at(_Tp* __location) { - __location->~_Tp(); + std::_Destroy(__location); } template <typename _ForwardIterator> inline void destroy(_ForwardIterator __first, _ForwardIterator __last) { - for (; __first != __last; ++__first) - std::destroy_at(std::__addressof(*__first)); + std::_Destroy(__first, __last); } template <typename _ForwardIterator, typename _Size> inline _ForwardIterator destroy_n(_ForwardIterator __first, _Size __count) { - for (; __count > 0; (void)++__first, --__count) - std::destroy_at(std::__addressof(*__first)); - return __first; + return std::_Destroy_n(__first, __count); } #endif diff --git a/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/1.cc b/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/1.cc index ec72b82..84a6857 100644 --- a/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/1.cc +++ b/libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/1.cc @@ -21,14 +21,40 @@ #include <testsuite_hooks.h> #include <string> #include <array> +#include <sstream> int del_count = 0; +int ctor_count = 0; +int throw_after = 0; struct DelCount { ~DelCount() { ++del_count; } }; +struct ThrowAfterN +{ + ThrowAfterN() + { + if (++ctor_count == throw_after) { + std::ostringstream os; + os << "ThrowAfterN(), ctor_count: " << ctor_count + << " throw_after: " << throw_after << std::endl; + throw std::runtime_error(os.str()); + } + } + ThrowAfterN(ThrowAfterN&&) + { + if (++ctor_count == throw_after) { + std::ostringstream os; + os << "ThrowAfterN(), ctor_count: " << ctor_count + << " throw_after: " << throw_after << std::endl; + throw std::runtime_error(os.str()); + } + } + DelCount dc; +}; + void test01() { char test_data[] = "123456"; @@ -118,6 +144,153 @@ void test09() free(target); } +void test10() +{ + char* x = (char*)malloc(sizeof(char)*10); + for (int i = 0; i < 10; ++i) new (x+i) char; + std::destroy(x, x+10); + free(x); +} + +void test11() +{ + char* x = (char*)malloc(sizeof(char)*10); + for (int i = 0; i < 10; ++i) new (x+i) char; + std::destroy_n(x, 10); + free(x); +} + +void test12() +{ + throw_after = 5; + del_count = 0; + ctor_count = 0; + ThrowAfterN* target = + (ThrowAfterN*)malloc(sizeof(ThrowAfterN)*10); + try { + std::uninitialized_default_construct(target, target+10); + } catch (...) { + } + VERIFY(ctor_count == 5); + VERIFY(del_count == 5); + throw_after = 0; + del_count = 0; + ctor_count = 0; +} + +void test13() +{ + throw_after = 5; + del_count = 0; + ctor_count = 0; + ThrowAfterN* target = + (ThrowAfterN*)malloc(sizeof(ThrowAfterN)*10); + try { + std::uninitialized_value_construct(target, target+10); + } catch (...) { + } + VERIFY(ctor_count == 5); + VERIFY(del_count == 5); + throw_after = 0; + del_count = 0; + ctor_count = 0; +} + +void test14() +{ + throw_after = 5; + del_count = 0; + ctor_count = 0; + ThrowAfterN* target = + (ThrowAfterN*)malloc(sizeof(ThrowAfterN)*10); + try { + std::uninitialized_default_construct_n(target, 10); + } catch (...) { + } + VERIFY(ctor_count == 5); + VERIFY(del_count == 5); + throw_after = 0; + del_count = 0; + ctor_count = 0; +} + +void test15() +{ + throw_after = 5; + del_count = 0; + ctor_count = 0; + ThrowAfterN* target = + (ThrowAfterN*)malloc(sizeof(ThrowAfterN)*10); + try { + std::uninitialized_value_construct_n(target, 10); + } catch (...) { + } + VERIFY(ctor_count == 5); + VERIFY(del_count == 5); + throw_after = 0; + del_count = 0; + ctor_count = 0; +} + +void test16() +{ + std::vector<ThrowAfterN> source(10); + del_count = 0; + ctor_count = 0; + throw_after = 5; + throw_after = 5; + ThrowAfterN* target = + (ThrowAfterN*)malloc(sizeof(ThrowAfterN)*10); + try { + std::uninitialized_move(source.begin(), source.end(), target); + } catch (...) { + } + VERIFY(ctor_count == 5); + VERIFY(del_count == 5); + throw_after = 0; + del_count = 0; + ctor_count = 0; +} + +void test17() +{ + std::vector<ThrowAfterN> source(10); + del_count = 0; + ctor_count = 0; + throw_after = 5; + ThrowAfterN* target = + (ThrowAfterN*)malloc(sizeof(ThrowAfterN)*10); + try { + std::uninitialized_move_n(source.begin(), 10, target); + } catch (...) { + } + VERIFY(ctor_count == 5); + VERIFY(del_count == 5); + throw_after = 0; + del_count = 0; + ctor_count = 0; +} + +void test18() +{ + char test_source[] = "123456"; + char test_target[] = "000000"; + std::uninitialized_move(std::begin(test_source), + std::end(test_source), + test_target); + VERIFY(std::string(test_target) == "123456"); +} + +void test19() +{ + char test_source[] = "123456"; + char test_target[] = "000000"; + std::uninitialized_move_n(std::begin(test_source), + 6, + test_target); + VERIFY(std::string(test_target) == "123456"); +} + int main() { test01(); @@ -129,4 +302,14 @@ int main() test07(); test08(); test09(); + test10(); + test11(); + test12(); + test13(); + test14(); + test15(); + test16(); + test17(); + test18(); + test19(); } |