From 8487ce681fdb78c0df4d756e5ed5099358f4943d Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Fri, 19 May 2023 12:47:02 -0700 Subject: [PATCH] Cleanup elements when `resize` fails in `deque(n)` Fixes #3717 --- stl/inc/deque | 2 + .../test.cpp | 64 +++++++++++++++++-- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/stl/inc/deque b/stl/inc/deque index 2fd2956fc3..0d84db3cd8 100644 --- a/stl/inc/deque +++ b/stl/inc/deque @@ -623,7 +623,9 @@ public: : _Mypair(_One_then_variadic_args_t{}, _Al) { _Alproxy_ty _Alproxy(_Getal()); _Container_proxy_ptr12<_Alproxy_ty> _Proxy(_Alproxy, _Get_data()); + _Tidy_guard _Guard{this}; resize(_Count); + _Guard._Target = nullptr; _Proxy._Release(); } diff --git a/tests/std/tests/GH_002769_handle_deque_block_pointers/test.cpp b/tests/std/tests/GH_002769_handle_deque_block_pointers/test.cpp index 2a9e63e4bc..28d2d7abf2 100644 --- a/tests/std/tests/GH_002769_handle_deque_block_pointers/test.cpp +++ b/tests/std/tests/GH_002769_handle_deque_block_pointers/test.cpp @@ -10,7 +10,7 @@ using namespace std; -size_t fancy_counter = 0; +size_t counter = 0; template class counting_ptr { @@ -18,7 +18,7 @@ class counting_ptr { T* p_; explicit counting_ptr(T* raw_ptr) noexcept : p_(raw_ptr) { - ++fancy_counter; + ++counter; } template @@ -48,8 +48,8 @@ class counting_ptr { } ~counting_ptr() { - assert(fancy_counter != 0); - --fancy_counter; + assert(counter != 0); + --counter; } explicit operator bool() const noexcept { @@ -211,17 +211,69 @@ struct ptr_counting_allocator { #endif // !_HAS_CXX20 }; +size_t count_limit = 0; + +struct live_counter { + live_counter() { + add(); + } + live_counter(const live_counter&) { + add(); + } + live_counter& operator=(const live_counter&) = default; + ~live_counter() { + remove(); + } + + static void add() { + assert(counter <= count_limit); + if (counter == count_limit) { + throw 42; + } + ++counter; + } + static void remove() { + assert(counter <= count_limit); + assert(counter > 0); + --counter; + } +}; + +void test_gh_3717() { + // Also test GH-3717: deque(count) would leak elements if a constructor threw during resize(count) + + // make sure the counter/limit machinery works properly + assert(counter == 0); + count_limit = 8; + { + deque d{8}; + assert(counter == 8); + } + assert(counter == 0); + + // verify that deque(n) cleans up live objects on construction failure + try { + deque{16}; + assert(false); + } catch (const int i) { + assert(i == 42); + assert(counter == 0); + } +} + int main() { { deque> dq{3, 1, 4, 1, 5, 9}; dq.insert(dq.end(), {2, 6, 5, 3, 5, 8}); } - assert(fancy_counter == 0); + assert(counter == 0); { deque> dq(979, 323); dq.insert(dq.begin(), 84, 62); dq.erase(dq.begin() + 64, dq.begin() + 338); } - assert(fancy_counter == 0); + assert(counter == 0); + + test_gh_3717(); }