]>
Commit | Line | Data |
---|---|---|
3157f602 XL |
1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
abe05a73 XL |
11 | // ignore-wasm32-bare compiled with panic=abort by default |
12 | ||
13 | #![feature(generators, generator_trait, untagged_unions)] | |
3157f602 XL |
14 | |
15 | use std::cell::{Cell, RefCell}; | |
abe05a73 | 16 | use std::ops::Generator; |
3157f602 XL |
17 | use std::panic; |
18 | use std::usize; | |
19 | ||
20 | struct InjectedFailure; | |
21 | ||
22 | struct Allocator { | |
23 | data: RefCell<Vec<bool>>, | |
24 | failing_op: usize, | |
25 | cur_ops: Cell<usize>, | |
26 | } | |
27 | ||
28 | impl panic::UnwindSafe for Allocator {} | |
29 | impl panic::RefUnwindSafe for Allocator {} | |
30 | ||
31 | impl Drop for Allocator { | |
32 | fn drop(&mut self) { | |
33 | let data = self.data.borrow(); | |
34 | if data.iter().any(|d| *d) { | |
35 | panic!("missing free: {:?}", data); | |
36 | } | |
37 | } | |
38 | } | |
39 | ||
40 | impl Allocator { | |
41 | fn new(failing_op: usize) -> Self { | |
42 | Allocator { | |
43 | failing_op: failing_op, | |
44 | cur_ops: Cell::new(0), | |
45 | data: RefCell::new(vec![]) | |
46 | } | |
47 | } | |
48 | fn alloc(&self) -> Ptr { | |
49 | self.cur_ops.set(self.cur_ops.get() + 1); | |
50 | ||
51 | if self.cur_ops.get() == self.failing_op { | |
52 | panic!(InjectedFailure); | |
53 | } | |
54 | ||
55 | let mut data = self.data.borrow_mut(); | |
56 | let addr = data.len(); | |
57 | data.push(true); | |
58 | Ptr(addr, self) | |
59 | } | |
60 | } | |
61 | ||
62 | struct Ptr<'a>(usize, &'a Allocator); | |
63 | impl<'a> Drop for Ptr<'a> { | |
64 | fn drop(&mut self) { | |
65 | match self.1.data.borrow_mut()[self.0] { | |
66 | false => { | |
67 | panic!("double free at index {:?}", self.0) | |
68 | } | |
69 | ref mut d => *d = false | |
70 | } | |
71 | ||
72 | self.1.cur_ops.set(self.1.cur_ops.get()+1); | |
73 | ||
74 | if self.1.cur_ops.get() == self.1.failing_op { | |
75 | panic!(InjectedFailure); | |
76 | } | |
77 | } | |
78 | } | |
79 | ||
3157f602 XL |
80 | fn dynamic_init(a: &Allocator, c: bool) { |
81 | let _x; | |
82 | if c { | |
83 | _x = Some(a.alloc()); | |
84 | } | |
85 | } | |
86 | ||
3157f602 XL |
87 | fn dynamic_drop(a: &Allocator, c: bool) { |
88 | let x = a.alloc(); | |
89 | if c { | |
90 | Some(x) | |
91 | } else { | |
92 | None | |
93 | }; | |
94 | } | |
95 | ||
7cac9316 XL |
96 | struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>); |
97 | fn struct_dynamic_drop(a: &Allocator, c0: bool, c1: bool, c: bool) { | |
98 | for i in 0..2 { | |
99 | let x; | |
100 | let y; | |
101 | if (c0 && i == 0) || (c1 && i == 1) { | |
102 | x = (a.alloc(), a.alloc(), a.alloc()); | |
103 | y = TwoPtrs(a.alloc(), a.alloc()); | |
104 | if c { | |
105 | drop(x.1); | |
106 | drop(y.0); | |
107 | } | |
108 | } | |
109 | } | |
110 | } | |
111 | ||
041b39d2 XL |
112 | fn field_assignment(a: &Allocator, c0: bool) { |
113 | let mut x = (TwoPtrs(a.alloc(), a.alloc()), a.alloc()); | |
114 | ||
115 | x.1 = a.alloc(); | |
116 | x.1 = a.alloc(); | |
117 | ||
118 | let f = (x.0).0; | |
119 | if c0 { | |
120 | (x.0).0 = f; | |
121 | } | |
122 | } | |
123 | ||
3157f602 XL |
124 | fn assignment2(a: &Allocator, c0: bool, c1: bool) { |
125 | let mut _v = a.alloc(); | |
126 | let mut _w = a.alloc(); | |
127 | if c0 { | |
128 | drop(_v); | |
129 | } | |
130 | _v = _w; | |
131 | if c1 { | |
132 | _w = a.alloc(); | |
133 | } | |
134 | } | |
135 | ||
3157f602 XL |
136 | fn assignment1(a: &Allocator, c0: bool) { |
137 | let mut _v = a.alloc(); | |
138 | let mut _w = a.alloc(); | |
139 | if c0 { | |
140 | drop(_v); | |
141 | } | |
142 | _v = _w; | |
143 | } | |
144 | ||
9e0c209e SL |
145 | #[allow(unions_with_drop_fields)] |
146 | union Boxy<T> { | |
147 | a: T, | |
148 | b: T, | |
149 | } | |
150 | ||
151 | fn union1(a: &Allocator) { | |
152 | unsafe { | |
153 | let mut u = Boxy { a: a.alloc() }; | |
154 | u.b = a.alloc(); | |
155 | drop(u.a); | |
156 | } | |
157 | } | |
158 | ||
7cac9316 XL |
159 | fn array_simple(a: &Allocator) { |
160 | let _x = [a.alloc(), a.alloc(), a.alloc(), a.alloc()]; | |
161 | } | |
162 | ||
163 | fn vec_simple(a: &Allocator) { | |
164 | let _x = vec![a.alloc(), a.alloc(), a.alloc(), a.alloc()]; | |
165 | } | |
166 | ||
abe05a73 XL |
167 | fn generator(a: &Allocator, run_count: usize) { |
168 | assert!(run_count < 4); | |
169 | ||
170 | let mut gen = || { | |
171 | (a.alloc(), | |
172 | yield a.alloc(), | |
173 | a.alloc(), | |
174 | yield a.alloc() | |
175 | ); | |
176 | }; | |
177 | for _ in 0..run_count { | |
178 | gen.resume(); | |
179 | } | |
180 | } | |
181 | ||
182 | fn mixed_drop_and_nondrop(a: &Allocator) { | |
183 | // check that destructor panics handle drop | |
184 | // and non-drop blocks in the same scope correctly. | |
185 | // | |
186 | // Surprisingly enough, this used to not work. | |
187 | let (x, y, z); | |
188 | x = a.alloc(); | |
189 | y = 5; | |
190 | z = a.alloc(); | |
191 | } | |
192 | ||
3b2f2976 XL |
193 | #[allow(unreachable_code)] |
194 | fn vec_unreachable(a: &Allocator) { | |
195 | let _x = vec![a.alloc(), a.alloc(), a.alloc(), return]; | |
196 | } | |
197 | ||
3157f602 XL |
198 | fn run_test<F>(mut f: F) |
199 | where F: FnMut(&Allocator) | |
200 | { | |
201 | let first_alloc = Allocator::new(usize::MAX); | |
202 | f(&first_alloc); | |
203 | ||
204 | for failing_op in 1..first_alloc.cur_ops.get()+1 { | |
205 | let alloc = Allocator::new(failing_op); | |
206 | let alloc = &alloc; | |
207 | let f = panic::AssertUnwindSafe(&mut f); | |
208 | let result = panic::catch_unwind(move || { | |
209 | f.0(alloc); | |
210 | }); | |
211 | match result { | |
212 | Ok(..) => panic!("test executed {} ops but now {}", | |
213 | first_alloc.cur_ops.get(), alloc.cur_ops.get()), | |
214 | Err(e) => { | |
215 | if e.downcast_ref::<InjectedFailure>().is_none() { | |
216 | panic::resume_unwind(e); | |
217 | } | |
218 | } | |
219 | } | |
220 | } | |
221 | } | |
222 | ||
9e0c209e SL |
223 | fn run_test_nopanic<F>(mut f: F) |
224 | where F: FnMut(&Allocator) | |
225 | { | |
226 | let first_alloc = Allocator::new(usize::MAX); | |
227 | f(&first_alloc); | |
228 | } | |
229 | ||
3157f602 XL |
230 | fn main() { |
231 | run_test(|a| dynamic_init(a, false)); | |
232 | run_test(|a| dynamic_init(a, true)); | |
233 | run_test(|a| dynamic_drop(a, false)); | |
234 | run_test(|a| dynamic_drop(a, true)); | |
235 | ||
236 | run_test(|a| assignment2(a, false, false)); | |
237 | run_test(|a| assignment2(a, false, true)); | |
238 | run_test(|a| assignment2(a, true, false)); | |
239 | run_test(|a| assignment2(a, true, true)); | |
240 | ||
241 | run_test(|a| assignment1(a, false)); | |
242 | run_test(|a| assignment1(a, true)); | |
9e0c209e | 243 | |
7cac9316 XL |
244 | run_test(|a| array_simple(a)); |
245 | run_test(|a| vec_simple(a)); | |
3b2f2976 | 246 | run_test(|a| vec_unreachable(a)); |
7cac9316 XL |
247 | |
248 | run_test(|a| struct_dynamic_drop(a, false, false, false)); | |
249 | run_test(|a| struct_dynamic_drop(a, false, false, true)); | |
250 | run_test(|a| struct_dynamic_drop(a, false, true, false)); | |
251 | run_test(|a| struct_dynamic_drop(a, false, true, true)); | |
252 | run_test(|a| struct_dynamic_drop(a, true, false, false)); | |
253 | run_test(|a| struct_dynamic_drop(a, true, false, true)); | |
254 | run_test(|a| struct_dynamic_drop(a, true, true, false)); | |
255 | run_test(|a| struct_dynamic_drop(a, true, true, true)); | |
256 | ||
041b39d2 XL |
257 | run_test(|a| field_assignment(a, false)); |
258 | run_test(|a| field_assignment(a, true)); | |
259 | ||
abe05a73 XL |
260 | run_test(|a| generator(a, 0)); |
261 | run_test(|a| generator(a, 1)); | |
262 | run_test(|a| generator(a, 2)); | |
263 | run_test(|a| generator(a, 3)); | |
264 | ||
265 | run_test(|a| mixed_drop_and_nondrop(a)); | |
266 | ||
9e0c209e | 267 | run_test_nopanic(|a| union1(a)); |
3157f602 | 268 | } |