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 // Test asan vector annotations with a class that throws in a CTOR.
11
12 #include <vector>
13 #include <cassert>
14
15 #include "test_macros.h"
16 #include "asan_testing.h"
17
18 class X {
19 public:
X(const X & x)20 X(const X &x) { Init(x.a); }
X(char arg)21 X(char arg) { Init(arg); }
X()22 X() { Init(42); }
operator =(const X & x)23 X &operator=(const X &x) {
24 Init(x.a);
25 return *this;
26 }
Init(char arg)27 void Init(char arg) {
28 if (arg == 42)
29 throw 0;
30 if (arg == 66)
31 arg = 42;
32 a = arg;
33 }
get() const34 char get() const { return a; }
set(char arg)35 void set(char arg) { a = arg; }
36
37 private:
38 char a;
39 };
40
41 class ThrowOnCopy {
42 public:
ThrowOnCopy()43 ThrowOnCopy() : should_throw(false) {}
ThrowOnCopy(bool xshould_throw)44 explicit ThrowOnCopy(bool xshould_throw) : should_throw(xshould_throw) {}
45
ThrowOnCopy(ThrowOnCopy const & other)46 ThrowOnCopy(ThrowOnCopy const & other)
47 : should_throw(other.should_throw)
48 {
49 if (should_throw) {
50 throw 0;
51 }
52 }
53 ThrowOnCopy& operator=(ThrowOnCopy const&) = default;
54
55 bool should_throw;
56 };
57
test_push_back()58 void test_push_back() {
59 std::vector<X> v;
60 v.reserve(2);
61 v.push_back(X(2));
62 assert(v.size() == 1);
63 try {
64 v.push_back(X(66));
65 assert(0);
66 } catch (int e) {
67 assert(v.size() == 1);
68 }
69 assert(v.size() == 1);
70 assert(is_contiguous_container_asan_correct(v));
71 }
72
test_emplace_back()73 void test_emplace_back() {
74 #if TEST_STD_VER >= 11
75 std::vector<X> v;
76 v.reserve(2);
77 v.push_back(X(2));
78 assert(v.size() == 1);
79 try {
80 v.emplace_back(42);
81 assert(0);
82 } catch (int e) {
83 assert(v.size() == 1);
84 }
85 assert(v.size() == 1);
86 assert(is_contiguous_container_asan_correct(v));
87 #endif
88 }
89
test_insert_range()90 void test_insert_range() {
91 std::vector<X> v;
92 v.reserve(4);
93 v.push_back(X(1));
94 v.push_back(X(2));
95 assert(v.size() == 2);
96 assert(v.capacity() >= 4);
97 try {
98 char a[2] = {21, 42};
99 v.insert(v.end(), a, a + 2);
100 assert(0);
101 } catch (int e) {
102 assert(v.size() == 2);
103 }
104 assert(v.size() == 2);
105 assert(is_contiguous_container_asan_correct(v));
106 }
107
test_insert()108 void test_insert() {
109 std::vector<X> v;
110 v.reserve(3);
111 v.insert(v.end(), X(1));
112 v.insert(v.begin(), X(2));
113 assert(v.size() == 2);
114 try {
115 v.insert(v.end(), X(66));
116 assert(0);
117 } catch (int e) {
118 assert(v.size() == 2);
119 }
120 assert(v.size() == 2);
121 assert(is_contiguous_container_asan_correct(v));
122 }
123
test_emplace()124 void test_emplace() {
125 #if TEST_STD_VER >= 11
126 std::vector<X> v;
127 v.reserve(3);
128 v.insert(v.end(), X(1));
129 v.insert(v.begin(), X(2));
130 assert(v.size() == 2);
131 try {
132 v.emplace(v.end(), 42);
133 assert(0);
134 } catch (int e) {
135 assert(v.size() == 2);
136 }
137 assert(v.size() == 2);
138 assert(is_contiguous_container_asan_correct(v));
139 #endif
140 }
141
test_insert_range2()142 void test_insert_range2() {
143 std::vector<X> v;
144 v.reserve(4);
145 v.insert(v.end(), X(1));
146 v.insert(v.begin(), X(2));
147 assert(v.size() == 2);
148 assert(v.capacity() >= 4);
149 try {
150 char a[2] = {10, 42};
151 v.insert(v.begin(), a, a + 2);
152 assert(0);
153 } catch (int e) {
154 assert(v.size() <= 4);
155 assert(is_contiguous_container_asan_correct(v));
156 return;
157 }
158 assert(0);
159 }
160
test_insert_n()161 void test_insert_n() {
162 std::vector<X> v;
163 v.reserve(10);
164 v.insert(v.end(), X(1));
165 v.insert(v.begin(), X(2));
166 assert(v.size() == 2);
167 try {
168 v.insert(v.begin(), 1, X(66));
169 assert(0);
170 } catch (int e) {
171 assert(v.size() <= 3);
172 assert(is_contiguous_container_asan_correct(v));
173 return;
174 }
175 assert(0);
176 }
177
178
test_insert_n2()179 void test_insert_n2() {
180 std::vector<ThrowOnCopy> v(10);
181 v.reserve(100);
182 assert(v.size() == 10);
183 v[6].should_throw = true;
184 try {
185 v.insert(v.cbegin(), 5, ThrowOnCopy());
186 assert(0);
187 } catch (int e) {
188 assert(v.size() == 11);
189 assert(is_contiguous_container_asan_correct(v));
190 return;
191 }
192 assert(0);
193 }
194
test_resize()195 void test_resize() {
196 std::vector<X> v;
197 v.reserve(3);
198 v.push_back(X(0));
199 try {
200 v.resize(3);
201 assert(0);
202 } catch (int e) {
203 assert(v.size() == 1);
204 }
205 assert(v.size() == 1);
206 assert(is_contiguous_container_asan_correct(v));
207 }
208
test_resize_param()209 void test_resize_param() {
210 std::vector<X> v;
211 v.reserve(3);
212 v.push_back(X(0));
213 try {
214 v.resize(3, X(66));
215 assert(0);
216 } catch (int e) {
217 assert(v.size() == 1);
218 }
219 assert(v.size() == 1);
220 assert(is_contiguous_container_asan_correct(v));
221 }
222
main(int,char **)223 int main(int, char**) {
224 test_push_back();
225 test_emplace_back();
226 test_insert_range();
227 test_insert();
228 test_emplace();
229 test_insert_range2();
230 test_insert_n();
231 test_insert_n2();
232 test_resize();
233 test_resize_param();
234
235 return 0;
236 }
237