1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: no-exceptions 10 11 // (bug report: https://llvm.org/PR58392) 12 // Check that vector<bool> constructors don't leak memory when an operation inside the constructor throws an exception 13 14 #include <type_traits> 15 #include <vector> 16 17 #include "count_new.h" 18 #include "test_iterators.h" 19 20 template <class T> 21 struct Allocator { 22 using value_type = T; 23 using is_always_equal = std::false_type; 24 25 template <class U> 26 Allocator(const Allocator<U>&) {} 27 28 Allocator(bool should_throw = true) { 29 if (should_throw) 30 throw 0; 31 } 32 33 T* allocate(int n) { return std::allocator<T>().allocate(n); } 34 void deallocate(T* ptr, int n) { std::allocator<T>().deallocate(ptr, n); } 35 36 friend bool operator==(const Allocator&, const Allocator&) { return false; } 37 }; 38 39 template <class IterCat> 40 struct Iterator { 41 using iterator_category = IterCat; 42 using difference_type = std::ptrdiff_t; 43 using value_type = bool; 44 using reference = bool&; 45 using pointer = bool*; 46 47 int i_; 48 bool b_ = true; 49 Iterator(int i = 0) : i_(i) {} 50 bool& operator*() { 51 if (i_ == 1) 52 throw 1; 53 return b_; 54 } 55 56 friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.i_ == rhs.i_; } 57 58 friend bool operator!=(const Iterator& lhs, const Iterator& rhs) { return lhs.i_ != rhs.i_; } 59 60 Iterator& operator++() { 61 ++i_; 62 return *this; 63 } 64 65 Iterator operator++(int) { 66 auto tmp = *this; 67 ++i_; 68 return tmp; 69 } 70 }; 71 72 void check_new_delete_called() { 73 assert(globalMemCounter.new_called == globalMemCounter.delete_called); 74 assert(globalMemCounter.new_array_called == globalMemCounter.delete_array_called); 75 assert(globalMemCounter.aligned_new_called == globalMemCounter.aligned_delete_called); 76 assert(globalMemCounter.aligned_new_array_called == globalMemCounter.aligned_delete_array_called); 77 } 78 79 int main(int, char**) { 80 using AllocVec = std::vector<bool, Allocator<bool> >; 81 82 #if TEST_STD_VER >= 14 83 try { // Throw in vector(size_type, const allocator_type&) from allocator 84 Allocator<bool> alloc(false); 85 AllocVec get_alloc(0, alloc); 86 } catch (int) { 87 } 88 check_new_delete_called(); 89 #endif // TEST_STD_VER >= 14 90 91 try { // Throw in vector(InputIterator, InputIterator) from input iterator 92 std::vector<bool> vec((Iterator<std::input_iterator_tag>()), Iterator<std::input_iterator_tag>(2)); 93 } catch (int) { 94 } 95 check_new_delete_called(); 96 97 try { // Throw in vector(InputIterator, InputIterator) from forward iterator 98 std::vector<bool> vec((Iterator<std::forward_iterator_tag>()), Iterator<std::forward_iterator_tag>(2)); 99 } catch (int) { 100 } 101 check_new_delete_called(); 102 103 try { // Throw in vector(InputIterator, InputIterator) from allocator 104 int a[] = {1, 2}; 105 AllocVec vec(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 2)); 106 } catch (int) { 107 } 108 check_new_delete_called(); 109 110 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from input iterator 111 std::allocator<bool> alloc; 112 std::vector<bool> vec(Iterator<std::input_iterator_tag>(), Iterator<std::input_iterator_tag>(2), alloc); 113 } catch (int) { 114 } 115 check_new_delete_called(); 116 117 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from forward iterator 118 std::allocator<bool> alloc; 119 std::vector<bool> vec(Iterator<std::forward_iterator_tag>(), Iterator<std::forward_iterator_tag>(2), alloc); 120 } catch (int) { 121 } 122 check_new_delete_called(); 123 124 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator 125 bool a[] = {true, false}; 126 Allocator<bool> alloc(false); 127 AllocVec vec(cpp17_input_iterator<bool*>(a), cpp17_input_iterator<bool*>(a + 2), alloc); 128 } catch (int) { 129 } 130 check_new_delete_called(); 131 132 try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator 133 bool a[] = {true, false}; 134 Allocator<bool> alloc(false); 135 AllocVec vec(forward_iterator<bool*>(a), forward_iterator<bool*>(a + 2), alloc); 136 } catch (int) { 137 } 138 check_new_delete_called(); 139 140 return 0; 141 } 142