Skip to content

Commit 8ff4d21

Browse files
committed
[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 e2f56de commit 8ff4d21

File tree

3 files changed

+437
-20
lines changed

3 files changed

+437
-20
lines changed

libcxx/include/vector

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ erase_if(vector<T, Allocator>& c, Predicate pred); // C++20
302302
#include <__utility/forward.h>
303303
#include <__utility/move.h>
304304
#include <__utility/swap.h>
305+
#include <__utility/transaction.h>
305306
#include <climits>
306307
#include <cstdlib>
307308
#include <cstring>
@@ -423,18 +424,27 @@ public:
423424
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
424425
vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a);
425426

426-
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
427-
~vector()
428-
{
429-
__annotate_delete();
430-
std::__debug_db_erase_c(this);
427+
private:
428+
class __destroy_vector {
429+
public:
430+
_LIBCPP_CONSTEXPR __destroy_vector(vector& __vec) : __vec_(__vec) {}
431431

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

439449
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(const vector& __x);
440450
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI vector(const vector& __x, const __type_identity_t<allocator_type>& __a);
@@ -1054,12 +1064,14 @@ template <class _Tp, class _Allocator>
10541064
_LIBCPP_CONSTEXPR_SINCE_CXX20
10551065
vector<_Tp, _Allocator>::vector(size_type __n)
10561066
{
1067+
auto __guard = std::__make_transaction(__destroy_vector(*this));
10571068
std::__debug_db_insert_c(this);
10581069
if (__n > 0)
10591070
{
10601071
__vallocate(__n);
10611072
__construct_at_end(__n);
10621073
}
1074+
__guard.__complete();
10631075
}
10641076

10651077
#if _LIBCPP_STD_VER > 11
@@ -1068,25 +1080,29 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20
10681080
vector<_Tp, _Allocator>::vector(size_type __n, const allocator_type& __a)
10691081
: __end_cap_(nullptr, __a)
10701082
{
1083+
auto __guard = std::__make_transaction(__destroy_vector(*this));
10711084
std::__debug_db_insert_c(this);
10721085
if (__n > 0)
10731086
{
10741087
__vallocate(__n);
10751088
__construct_at_end(__n);
10761089
}
1090+
__guard.__complete();
10771091
}
10781092
#endif
10791093

10801094
template <class _Tp, class _Allocator>
10811095
_LIBCPP_CONSTEXPR_SINCE_CXX20
10821096
vector<_Tp, _Allocator>::vector(size_type __n, const value_type& __x)
10831097
{
1098+
auto __guard = std::__make_transaction(__destroy_vector(*this));
10841099
std::__debug_db_insert_c(this);
10851100
if (__n > 0)
10861101
{
10871102
__vallocate(__n);
10881103
__construct_at_end(__n, __x);
10891104
}
1105+
__guard.__complete();
10901106
}
10911107

10921108
template <class _Tp, class _Allocator>
@@ -1096,9 +1112,11 @@ template <class _InputIterator, __enable_if_t<__is_exactly_cpp17_input_iterator<
10961112
_LIBCPP_CONSTEXPR_SINCE_CXX20
10971113
vector<_Tp, _Allocator>::vector(_InputIterator __first, _InputIterator __last)
10981114
{
1115+
auto __guard = std::__make_transaction(__destroy_vector(*this));
10991116
std::__debug_db_insert_c(this);
11001117
for (; __first != __last; ++__first)
11011118
emplace_back(*__first);
1119+
__guard.__complete();
11021120
}
11031121

11041122
template <class _Tp, class _Allocator>
@@ -1109,9 +1127,11 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20
11091127
vector<_Tp, _Allocator>::vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a)
11101128
: __end_cap_(nullptr, __a)
11111129
{
1130+
auto __guard = std::__make_transaction(__destroy_vector(*this));
11121131
std::__debug_db_insert_c(this);
11131132
for (; __first != __last; ++__first)
11141133
emplace_back(*__first);
1134+
__guard.__complete();
11151135
}
11161136

11171137
template <class _Tp, class _Allocator>
@@ -1121,13 +1141,15 @@ template <class _ForwardIterator, __enable_if_t<__is_cpp17_forward_iterator<_For
11211141
_LIBCPP_CONSTEXPR_SINCE_CXX20
11221142
vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last)
11231143
{
1144+
auto __guard = std::__make_transaction(__destroy_vector(*this));
11241145
std::__debug_db_insert_c(this);
11251146
size_type __n = static_cast<size_type>(std::distance(__first, __last));
11261147
if (__n > 0)
11271148
{
11281149
__vallocate(__n);
11291150
__construct_at_end(__first, __last, __n);
11301151
}
1152+
__guard.__complete();
11311153
}
11321154

11331155
template <class _Tp, class _Allocator>
@@ -1138,41 +1160,47 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20
11381160
vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a)
11391161
: __end_cap_(nullptr, __a)
11401162
{
1163+
auto __guard = std::__make_transaction(__destroy_vector(*this));
11411164
std::__debug_db_insert_c(this);
11421165
size_type __n = static_cast<size_type>(std::distance(__first, __last));
11431166
if (__n > 0)
11441167
{
11451168
__vallocate(__n);
11461169
__construct_at_end(__first, __last, __n);
11471170
}
1171+
__guard.__complete();
11481172
}
11491173

11501174
template <class _Tp, class _Allocator>
11511175
_LIBCPP_CONSTEXPR_SINCE_CXX20
11521176
vector<_Tp, _Allocator>::vector(const vector& __x)
11531177
: __end_cap_(nullptr, __alloc_traits::select_on_container_copy_construction(__x.__alloc()))
11541178
{
1179+
auto __guard = std::__make_transaction(__destroy_vector(*this));
11551180
std::__debug_db_insert_c(this);
11561181
size_type __n = __x.size();
11571182
if (__n > 0)
11581183
{
11591184
__vallocate(__n);
11601185
__construct_at_end(__x.__begin_, __x.__end_, __n);
11611186
}
1187+
__guard.__complete();
11621188
}
11631189

11641190
template <class _Tp, class _Allocator>
11651191
_LIBCPP_CONSTEXPR_SINCE_CXX20
11661192
vector<_Tp, _Allocator>::vector(const vector& __x, const __type_identity_t<allocator_type>& __a)
11671193
: __end_cap_(nullptr, __a)
11681194
{
1195+
auto __guard = std::__make_transaction(__destroy_vector(*this));
11691196
std::__debug_db_insert_c(this);
11701197
size_type __n = __x.size();
11711198
if (__n > 0)
11721199
{
11731200
__vallocate(__n);
11741201
__construct_at_end(__x.__begin_, __x.__end_, __n);
11751202
}
1203+
__guard.__complete();
11761204
}
11771205

11781206
template <class _Tp, class _Allocator>
@@ -1212,7 +1240,9 @@ vector<_Tp, _Allocator>::vector(vector&& __x, const __type_identity_t<allocator_
12121240
else
12131241
{
12141242
typedef move_iterator<iterator> _Ip;
1243+
auto __guard = std::__make_transaction(__destroy_vector(*this));
12151244
assign(_Ip(__x.begin()), _Ip(__x.end()));
1245+
__guard.__complete();
12161246
}
12171247
}
12181248

@@ -1223,12 +1253,14 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20
12231253
inline _LIBCPP_HIDE_FROM_ABI
12241254
vector<_Tp, _Allocator>::vector(initializer_list<value_type> __il)
12251255
{
1256+
auto __guard = std::__make_transaction(__destroy_vector(*this));
12261257
std::__debug_db_insert_c(this);
12271258
if (__il.size() > 0)
12281259
{
12291260
__vallocate(__il.size());
12301261
__construct_at_end(__il.begin(), __il.end(), __il.size());
12311262
}
1263+
__guard.__complete();
12321264
}
12331265

12341266
template <class _Tp, class _Allocator>
@@ -1237,12 +1269,14 @@ inline _LIBCPP_HIDE_FROM_ABI
12371269
vector<_Tp, _Allocator>::vector(initializer_list<value_type> __il, const allocator_type& __a)
12381270
: __end_cap_(nullptr, __a)
12391271
{
1272+
auto __guard = std::__make_transaction(__destroy_vector(*this));
12401273
std::__debug_db_insert_c(this);
12411274
if (__il.size() > 0)
12421275
{
12431276
__vallocate(__il.size());
12441277
__construct_at_end(__il.begin(), __il.end(), __il.size());
12451278
}
1279+
__guard.__complete();
12461280
}
12471281

12481282
#endif // _LIBCPP_CXX03_LANG
@@ -2060,7 +2094,25 @@ public:
20602094
#else
20612095
_NOEXCEPT;
20622096
#endif
2063-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~vector();
2097+
2098+
private:
2099+
class __destroy_vector {
2100+
public:
2101+
_LIBCPP_CONSTEXPR __destroy_vector(vector& __vec) : __vec_(__vec) {}
2102+
2103+
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void operator()() {
2104+
if (__vec_.__begin_ != nullptr)
2105+
__storage_traits::deallocate(__vec_.__alloc(), __vec_.__begin_, __vec_.__cap());
2106+
std::__debug_db_invalidate_all(this);
2107+
}
2108+
2109+
private:
2110+
vector& __vec_;
2111+
};
2112+
2113+
public:
2114+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~vector() { __destroy_vector(*this)(); }
2115+
20642116
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit vector(size_type __n);
20652117
#if _LIBCPP_STD_VER > 11
20662118
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit vector(size_type __n, const allocator_type& __a);
@@ -2596,12 +2648,14 @@ vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __la
25962648
__size_(0),
25972649
__cap_alloc_(0, __default_init_tag())
25982650
{
2651+
auto __guard = std::__make_transaction(__destroy_vector(*this));
25992652
size_type __n = static_cast<size_type>(std::distance(__first, __last));
26002653
if (__n > 0)
26012654
{
26022655
__vallocate(__n);
26032656
__construct_at_end(__first, __last);
26042657
}
2658+
__guard.__complete();
26052659
}
26062660

26072661
template <class _Allocator>
@@ -2613,12 +2667,14 @@ vector<bool, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __la
26132667
__size_(0),
26142668
__cap_alloc_(0, static_cast<__storage_allocator>(__a))
26152669
{
2670+
auto __guard = std::__make_transaction(__destroy_vector(*this));
26162671
size_type __n = static_cast<size_type>(std::distance(__first, __last));
26172672
if (__n > 0)
26182673
{
26192674
__vallocate(__n);
26202675
__construct_at_end(__first, __last);
26212676
}
2677+
__guard.__complete();
26222678
}
26232679

26242680
#ifndef _LIBCPP_CXX03_LANG
@@ -2655,15 +2711,6 @@ vector<bool, _Allocator>::vector(initializer_list<value_type> __il, const alloca
26552711

26562712
#endif // _LIBCPP_CXX03_LANG
26572713

2658-
template <class _Allocator>
2659-
_LIBCPP_CONSTEXPR_SINCE_CXX20
2660-
vector<bool, _Allocator>::~vector()
2661-
{
2662-
if (__begin_ != nullptr)
2663-
__storage_traits::deallocate(__alloc(), __begin_, __cap());
2664-
std::__debug_db_invalidate_all(this);
2665-
}
2666-
26672714
template <class _Allocator>
26682715
_LIBCPP_CONSTEXPR_SINCE_CXX20
26692716
vector<bool, _Allocator>::vector(const vector& __v)

0 commit comments

Comments
 (0)