aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVille Voutilainen <ville.voutilainen@gmail.com>2016-09-20 18:15:36 +0300
committerVille Voutilainen <ville@gcc.gnu.org>2016-09-20 18:15:36 +0300
commit377f30c00f3b8b8b0da748dbb9d988fa67a8ec2f (patch)
tree356ee8f4d2f55dc7174b1dfcb39e330821546d25
parent7d9cf8015969054f044ee815f0308e7130c59b83 (diff)
downloadgcc-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/ChangeLog27
-rw-r--r--libstdc++-v3/include/bits/stl_construct.h45
-rw-r--r--libstdc++-v3/include/bits/stl_uninitialized.h185
-rw-r--r--libstdc++-v3/testsuite/20_util/specialized_algorithms/memory_management_tools/1.cc183
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();
}