Skip to content

Commit 8dfdcc7

Browse files
philnik777tstellar
authored andcommitted
[libc++] Fix memory leaks when throwing inside std::vector constructors
Fixes #58392 Reviewed By: ldionne, #libc Spies: alexfh, hans, joanahalili, dblaikie, libcxx-commits Differential Revision: https://reviews.llvm.org/D138601
1 parent 939f5a3 commit 8dfdcc7

File tree

3 files changed

+453
-36
lines changed

3 files changed

+453
-36
lines changed

libcxx/include/vector

+83-36
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ erase_if(vector<T, Allocator>& c, Predicate pred); // C++20
297297
#include <__utility/forward.h>
298298
#include <__utility/move.h>
299299
#include <__utility/swap.h>
300+
#include <__utility/transaction.h>
300301
#include <climits>
301302
#include <cstdlib>
302303
#include <cstring>
@@ -425,18 +426,27 @@ public:
425426
value_type,
426427
typename iterator_traits<_ForwardIterator>::reference>::value>::type* = 0);
427428

428-
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY
429-
~vector()
430-
{
431-
__annotate_delete();
432-
std::__debug_db_erase_c(this);
429+
private:
430+
class __destroy_vector {
431+
public:
432+
_LIBCPP_CONSTEXPR __destroy_vector(vector& __vec) : __vec_(__vec) {}
433433

434-
if (this->__begin_ != nullptr)
435-
{
436-
__clear();
437-
__alloc_traits::deallocate(__alloc(), this->__begin_, capacity());
434+
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI void operator()() {
435+
__vec_.__annotate_delete();
436+
std::__debug_db_erase_c(std::addressof(__vec_));
437+
438+
if (__vec_.__begin_ != nullptr) {
439+
__vec_.__clear();
440+
__alloc_traits::deallocate(__vec_.__alloc(), __vec_.__begin_, __vec_.capacity());
441+
}
438442
}
439-
}
443+
444+
private:
445+
vector& __vec_;
446+
};
447+
448+
public:
449+
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI ~vector() { __destroy_vector(*this)(); }
440450

441451
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(const vector& __x);
442452
_LIBCPP_CONSTEXPR_AFTER_CXX17 vector(const vector& __x, const __type_identity_t<allocator_type>& __a);
@@ -1075,12 +1085,14 @@ template <class _Tp, class _Allocator>
10751085
_LIBCPP_CONSTEXPR_AFTER_CXX17
10761086
vector<_Tp, _Allocator>::vector(size_type __n)
10771087
{
1078-
_VSTD::__debug_db_insert_c(this);
1088+
auto __guard = std::__make_transaction(__destroy_vector(*this));
1089+
std::__debug_db_insert_c(this);
10791090
if (__n > 0)
10801091
{
10811092
__vallocate(__n);
10821093
__construct_at_end(__n);
10831094
}
1095+
__guard.__complete();
10841096
}
10851097

10861098
#if _LIBCPP_STD_VER > 11
@@ -1089,25 +1101,29 @@ _LIBCPP_CONSTEXPR_AFTER_CXX17
10891101
vector<_Tp, _Allocator>::vector(size_type __n, const allocator_type& __a)
10901102
: __end_cap_(nullptr, __a)
10911103
{
1092-
_VSTD::__debug_db_insert_c(this);
1104+
auto __guard = std::__make_transaction(__destroy_vector(*this));
1105+
std::__debug_db_insert_c(this);
10931106
if (__n > 0)
10941107
{
10951108
__vallocate(__n);
10961109
__construct_at_end(__n);
10971110
}
1111+
__guard.__complete();
10981112
}
10991113
#endif
11001114

11011115
template <class _Tp, class _Allocator>
11021116
_LIBCPP_CONSTEXPR_AFTER_CXX17
11031117
vector<_Tp, _Allocator>::vector(size_type __n, const value_type& __x)
11041118
{
1105-
_VSTD::__debug_db_insert_c(this);
1119+
auto __guard = std::__make_transaction(__destroy_vector(*this));
1120+
std::__debug_db_insert_c(this);
11061121
if (__n > 0)
11071122
{
11081123
__vallocate(__n);
11091124
__construct_at_end(__n, __x);
11101125
}
1126+
__guard.__complete();
11111127
}
11121128

11131129
template <class _Tp, class _Allocator>
@@ -1120,9 +1136,11 @@ vector<_Tp, _Allocator>::vector(_InputIterator __first,
11201136
typename iterator_traits<_InputIterator>::reference>::value,
11211137
_InputIterator>::type __last)
11221138
{
1123-
_VSTD::__debug_db_insert_c(this);
1139+
auto __guard = std::__make_transaction(__destroy_vector(*this));
1140+
std::__debug_db_insert_c(this);
11241141
for (; __first != __last; ++__first)
11251142
emplace_back(*__first);
1143+
__guard.__complete();
11261144
}
11271145

11281146
template <class _Tp, class _Allocator>
@@ -1135,9 +1153,11 @@ vector<_Tp, _Allocator>::vector(_InputIterator __first, _InputIterator __last, c
11351153
typename iterator_traits<_InputIterator>::reference>::value>::type*)
11361154
: __end_cap_(nullptr, __a)
11371155
{
1138-
_VSTD::__debug_db_insert_c(this);
1156+
auto __guard = std::__make_transaction(__destroy_vector(*this));
1157+
std::__debug_db_insert_c(this);
11391158
for (; __first != __last; ++__first)
11401159
emplace_back(*__first);
1160+
__guard.__complete();
11411161
}
11421162

11431163
template <class _Tp, class _Allocator>
@@ -1150,13 +1170,15 @@ vector<_Tp, _Allocator>::vector(_ForwardIterator __first,
11501170
typename iterator_traits<_ForwardIterator>::reference>::value,
11511171
_ForwardIterator>::type __last)
11521172
{
1153-
_VSTD::__debug_db_insert_c(this);
1154-
size_type __n = static_cast<size_type>(_VSTD::distance(__first, __last));
1173+
auto __guard = std::__make_transaction(__destroy_vector(*this));
1174+
std::__debug_db_insert_c(this);
1175+
size_type __n = static_cast<size_type>(std::distance(__first, __last));
11551176
if (__n > 0)
11561177
{
11571178
__vallocate(__n);
11581179
__construct_at_end(__first, __last, __n);
11591180
}
1181+
__guard.__complete();
11601182
}
11611183

11621184
template <class _Tp, class _Allocator>
@@ -1169,41 +1191,47 @@ vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __las
11691191
typename iterator_traits<_ForwardIterator>::reference>::value>::type*)
11701192
: __end_cap_(nullptr, __a)
11711193
{
1172-
_VSTD::__debug_db_insert_c(this);
1173-
size_type __n = static_cast<size_type>(_VSTD::distance(__first, __last));
1194+
auto __guard = std::__make_transaction(__destroy_vector(*this));
1195+
std::__debug_db_insert_c(this);
1196+
size_type __n = static_cast<size_type>(std::distance(__first, __last));
11741197
if (__n > 0)
11751198
{
11761199
__vallocate(__n);
11771200
__construct_at_end(__first, __last, __n);
11781201
}
1202+
__guard.__complete();
11791203
}
11801204

11811205
template <class _Tp, class _Allocator>
11821206
_LIBCPP_CONSTEXPR_AFTER_CXX17
11831207
vector<_Tp, _Allocator>::vector(const vector& __x)
11841208
: __end_cap_(nullptr, __alloc_traits::select_on_container_copy_construction(__x.__alloc()))
11851209
{
1186-
_VSTD::__debug_db_insert_c(this);
1210+
auto __guard = std::__make_transaction(__destroy_vector(*this));
1211+
std::__debug_db_insert_c(this);
11871212
size_type __n = __x.size();
11881213
if (__n > 0)
11891214
{
11901215
__vallocate(__n);
11911216
__construct_at_end(__x.__begin_, __x.__end_, __n);
11921217
}
1218+
__guard.__complete();
11931219
}
11941220

11951221
template <class _Tp, class _Allocator>
11961222
_LIBCPP_CONSTEXPR_AFTER_CXX17
11971223
vector<_Tp, _Allocator>::vector(const vector& __x, const __type_identity_t<allocator_type>& __a)
11981224
: __end_cap_(nullptr, __a)
11991225
{
1200-
_VSTD::__debug_db_insert_c(this);
1226+
auto __guard = std::__make_transaction(__destroy_vector(*this));
1227+
std::__debug_db_insert_c(this);
12011228
size_type __n = __x.size();
12021229
if (__n > 0)
12031230
{
12041231
__vallocate(__n);
12051232
__construct_at_end(__x.__begin_, __x.__end_, __n);
12061233
}
1234+
__guard.__complete();
12071235
}
12081236

12091237
template <class _Tp, class _Allocator>
@@ -1243,7 +1271,9 @@ vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t<allocator_
12431271
else
12441272
{
12451273
typedef move_iterator<iterator> _Ip;
1274+
auto __guard = std::__make_transaction(__destroy_vector(*this));
12461275
assign(_Ip(__x.begin()), _Ip(__x.end()));
1276+
__guard.__complete();
12471277
}
12481278
}
12491279

@@ -1254,12 +1284,14 @@ _LIBCPP_CONSTEXPR_AFTER_CXX17
12541284
inline _LIBCPP_INLINE_VISIBILITY
12551285
vector<_Tp, _Allocator>::vector(initializer_list<value_type> __il)
12561286
{
1257-
_VSTD::__debug_db_insert_c(this);
1287+
auto __guard = std::__make_transaction(__destroy_vector(*this));
1288+
std::__debug_db_insert_c(this);
12581289
if (__il.size() > 0)
12591290
{
12601291
__vallocate(__il.size());
12611292
__construct_at_end(__il.begin(), __il.end(), __il.size());
12621293
}
1294+
__guard.__complete();
12631295
}
12641296

12651297
template <class _Tp, class _Allocator>
@@ -1268,12 +1300,14 @@ inline _LIBCPP_INLINE_VISIBILITY
12681300
vector<_Tp, _Allocator>::vector(initializer_list<value_type> __il, const allocator_type& __a)
12691301
: __end_cap_(nullptr, __a)
12701302
{
1271-
_VSTD::__debug_db_insert_c(this);
1303+
auto __guard = std::__make_transaction(__destroy_vector(*this));
1304+
std::__debug_db_insert_c(this);
12721305
if (__il.size() > 0)
12731306
{
12741307
__vallocate(__il.size());
12751308
__construct_at_end(__il.begin(), __il.end(), __il.size());
12761309
}
1310+
__guard.__complete();
12771311
}
12781312

12791313
#endif // _LIBCPP_CXX03_LANG
@@ -2111,8 +2145,26 @@ public:
21112145
#else
21122146
_NOEXCEPT;
21132147
#endif
2114-
_LIBCPP_CONSTEXPR_AFTER_CXX17 ~vector();
2115-
_LIBCPP_CONSTEXPR_AFTER_CXX17 explicit vector(size_type __n);
2148+
2149+
private:
2150+
class __destroy_vector {
2151+
public:
2152+
_LIBCPP_CONSTEXPR __destroy_vector(vector& __vec) : __vec_(__vec) {}
2153+
2154+
_LIBCPP_CONSTEXPR_AFTER_CXX17 _LIBCPP_HIDE_FROM_ABI void operator()() {
2155+
if (__vec_.__begin_ != nullptr)
2156+
__storage_traits::deallocate(__vec_.__alloc(), __vec_.__begin_, __vec_.__cap());
2157+
std::__debug_db_invalidate_all(this);
2158+
}
2159+
2160+
private:
2161+
vector& __vec_;
2162+
};
2163+
2164+
public:
2165+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 ~vector() { __destroy_vector(*this)(); }
2166+
2167+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 explicit vector(size_type __n);
21162168
#if _LIBCPP_STD_VER > 11
21172169
_LIBCPP_CONSTEXPR_AFTER_CXX17 explicit vector(size_type __n, const allocator_type& __a);
21182170
#endif
@@ -2647,12 +2699,14 @@ vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __la
26472699
__size_(0),
26482700
__cap_alloc_(0, __default_init_tag())
26492701
{
2650-
size_type __n = static_cast<size_type>(_VSTD::distance(__first, __last));
2702+
auto __guard = std::__make_transaction(__destroy_vector(*this));
2703+
size_type __n = static_cast<size_type>(std::distance(__first, __last));
26512704
if (__n > 0)
26522705
{
26532706
__vallocate(__n);
26542707
__construct_at_end(__first, __last);
26552708
}
2709+
__guard.__complete();
26562710
}
26572711

26582712
template <class _Allocator>
@@ -2664,12 +2718,14 @@ vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __la
26642718
__size_(0),
26652719
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
26662720
{
2667-
size_type __n = static_cast<size_type>(_VSTD::distance(__first, __last));
2721+
auto __guard = std::__make_transaction(__destroy_vector(*this));
2722+
size_type __n = static_cast<size_type>(std::distance(__first, __last));
26682723
if (__n > 0)
26692724
{
26702725
__vallocate(__n);
26712726
__construct_at_end(__first, __last);
26722727
}
2728+
__guard.__complete();
26732729
}
26742730

26752731
#ifndef _LIBCPP_CXX03_LANG
@@ -2706,15 +2762,6 @@ vector<bool, _Allocator>::vector(initializer_list<value_type> __il, const alloca
27062762

27072763
#endif // _LIBCPP_CXX03_LANG
27082764

2709-
template <class _Allocator>
2710-
_LIBCPP_CONSTEXPR_AFTER_CXX17
2711-
vector<bool, _Allocator>::~vector()
2712-
{
2713-
if (__begin_ != nullptr)
2714-
__storage_traits::deallocate(__alloc(), __begin_, __cap());
2715-
std::__debug_db_invalidate_all(this);
2716-
}
2717-
27182765
template <class _Allocator>
27192766
_LIBCPP_CONSTEXPR_AFTER_CXX17
27202767
vector<bool, _Allocator>::vector(const vector& __v)

0 commit comments

Comments
 (0)