1 // run-pass
2 // ignore-wasm32-bare compiled with panic=abort by default
3 
4 #![feature(generators, generator_trait)]
5 
6 #![allow(unused_assignments)]
7 #![allow(unused_variables)]
8 
9 use std::cell::{Cell, RefCell};
10 use std::mem::ManuallyDrop;
11 use std::ops::Generator;
12 use std::panic;
13 use std::pin::Pin;
14 
15 struct InjectedFailure;
16 
17 struct Allocator {
18     data: RefCell<Vec<bool>>,
19     failing_op: usize,
20     cur_ops: Cell<usize>,
21 }
22 
23 impl panic::UnwindSafe for Allocator {}
24 impl panic::RefUnwindSafe for Allocator {}
25 
26 impl Drop for Allocator {
drop(&mut self)27     fn drop(&mut self) {
28         let data = self.data.borrow();
29         if data.iter().any(|d| *d) {
30             panic!("missing free: {:?}", data);
31         }
32     }
33 }
34 
35 impl Allocator {
new(failing_op: usize) -> Self36     fn new(failing_op: usize) -> Self {
37         Allocator {
38             failing_op: failing_op,
39             cur_ops: Cell::new(0),
40             data: RefCell::new(vec![])
41         }
42     }
alloc(&self) -> Ptr<'_>43     fn alloc(&self) -> Ptr<'_> {
44         self.cur_ops.set(self.cur_ops.get() + 1);
45 
46         if self.cur_ops.get() == self.failing_op {
47             panic::panic_any(InjectedFailure);
48         }
49 
50         let mut data = self.data.borrow_mut();
51         let addr = data.len();
52         data.push(true);
53         Ptr(addr, self)
54     }
55     // FIXME(#47949) Any use of this indicates a bug in rustc: we should never
56     // be leaking values in the cases here.
57     //
58     // Creates a `Ptr<'_>` and checks that the allocated value is leaked if the
59     // `failing_op` is in the list of exception.
alloc_leaked(&self, exceptions: Vec<usize>) -> Ptr<'_>60     fn alloc_leaked(&self, exceptions: Vec<usize>) -> Ptr<'_> {
61         let ptr = self.alloc();
62 
63         if exceptions.iter().any(|operation| *operation == self.failing_op) {
64             let mut data = self.data.borrow_mut();
65             data[ptr.0] = false;
66         }
67         ptr
68     }
69 }
70 
71 struct Ptr<'a>(usize, &'a Allocator);
72 impl<'a> Drop for Ptr<'a> {
drop(&mut self)73     fn drop(&mut self) {
74         match self.1.data.borrow_mut()[self.0] {
75             false => {
76                 panic!("double free at index {:?}", self.0)
77             }
78             ref mut d => *d = false
79         }
80 
81         self.1.cur_ops.set(self.1.cur_ops.get()+1);
82 
83         if self.1.cur_ops.get() == self.1.failing_op {
84             panic::panic_any(InjectedFailure);
85         }
86     }
87 }
88 
dynamic_init(a: &Allocator, c: bool)89 fn dynamic_init(a: &Allocator, c: bool) {
90     let _x;
91     if c {
92         _x = Some(a.alloc());
93     }
94 }
95 
dynamic_drop(a: &Allocator, c: bool)96 fn dynamic_drop(a: &Allocator, c: bool) {
97     let x = a.alloc();
98     if c {
99         Some(x)
100     } else {
101         None
102     };
103 }
104 
105 struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>);
struct_dynamic_drop(a: &Allocator, c0: bool, c1: bool, c: bool)106 fn struct_dynamic_drop(a: &Allocator, c0: bool, c1: bool, c: bool) {
107     for i in 0..2 {
108         let x;
109         let y;
110         if (c0 && i == 0) || (c1 && i == 1) {
111             x = (a.alloc(), a.alloc(), a.alloc());
112             y = TwoPtrs(a.alloc(), a.alloc());
113             if c {
114                 drop(x.1);
115                 drop(y.0);
116             }
117         }
118     }
119 }
120 
field_assignment(a: &Allocator, c0: bool)121 fn field_assignment(a: &Allocator, c0: bool) {
122     let mut x = (TwoPtrs(a.alloc(), a.alloc()), a.alloc());
123 
124     x.1 = a.alloc();
125     x.1 = a.alloc();
126 
127     let f = (x.0).0;
128     if c0 {
129         (x.0).0 = f;
130     }
131 }
132 
assignment2(a: &Allocator, c0: bool, c1: bool)133 fn assignment2(a: &Allocator, c0: bool, c1: bool) {
134     let mut _v = a.alloc();
135     let mut _w = a.alloc();
136     if c0 {
137         drop(_v);
138     }
139     _v = _w;
140     if c1 {
141         _w = a.alloc();
142     }
143 }
144 
assignment1(a: &Allocator, c0: bool)145 fn assignment1(a: &Allocator, c0: bool) {
146     let mut _v = a.alloc();
147     let mut _w = a.alloc();
148     if c0 {
149         drop(_v);
150     }
151     _v = _w;
152 }
153 
154 union Boxy<T> {
155     a: ManuallyDrop<T>,
156     b: ManuallyDrop<T>,
157 }
158 
union1(a: &Allocator)159 fn union1(a: &Allocator) {
160     unsafe {
161         let mut u = Boxy { a: ManuallyDrop::new(a.alloc()) };
162         *u.b = a.alloc(); // drops first alloc
163         drop(ManuallyDrop::into_inner(u.a));
164     }
165 }
166 
array_simple(a: &Allocator)167 fn array_simple(a: &Allocator) {
168     let _x = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
169 }
170 
vec_simple(a: &Allocator)171 fn vec_simple(a: &Allocator) {
172     let _x = vec![a.alloc(), a.alloc(), a.alloc(), a.alloc()];
173 }
174 
generator(a: &Allocator, run_count: usize)175 fn generator(a: &Allocator, run_count: usize) {
176     assert!(run_count < 4);
177 
178     let mut gen = || {
179         (a.alloc(),
180          yield a.alloc(),
181          a.alloc(),
182          yield a.alloc()
183          );
184     };
185     for _ in 0..run_count {
186         Pin::new(&mut gen).resume(());
187     }
188 }
189 
mixed_drop_and_nondrop(a: &Allocator)190 fn mixed_drop_and_nondrop(a: &Allocator) {
191     // check that destructor panics handle drop
192     // and non-drop blocks in the same scope correctly.
193     //
194     // Surprisingly enough, this used to not work.
195     let (x, y, z);
196     x = a.alloc();
197     y = 5;
198     z = a.alloc();
199 }
200 
201 #[allow(unreachable_code)]
vec_unreachable(a: &Allocator)202 fn vec_unreachable(a: &Allocator) {
203     let _x = vec![a.alloc(), a.alloc(), a.alloc(), return];
204 }
205 
slice_pattern_first(a: &Allocator)206 fn slice_pattern_first(a: &Allocator) {
207     let[_x, ..] = [a.alloc(), a.alloc(), a.alloc()];
208 }
209 
slice_pattern_middle(a: &Allocator)210 fn slice_pattern_middle(a: &Allocator) {
211     let[_, _x, _] = [a.alloc(), a.alloc(), a.alloc()];
212 }
213 
slice_pattern_two(a: &Allocator)214 fn slice_pattern_two(a: &Allocator) {
215     let[_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
216 }
217 
slice_pattern_last(a: &Allocator)218 fn slice_pattern_last(a: &Allocator) {
219     let[.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
220 }
221 
slice_pattern_one_of(a: &Allocator, i: usize)222 fn slice_pattern_one_of(a: &Allocator, i: usize) {
223     let array = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
224     let _x = match i {
225         0 => { let [a, ..] = array; a }
226         1 => { let [_, a, ..] = array; a }
227         2 => { let [_, _, a, _] = array; a }
228         3 => { let [_, _, _, a] = array; a }
229         _ => panic!("unmatched"),
230     };
231 }
232 
subslice_pattern_from_end(a: &Allocator, arg: bool)233 fn subslice_pattern_from_end(a: &Allocator, arg: bool) {
234     let a = [a.alloc(), a.alloc(), a.alloc()];
235     if arg {
236         let[.., _x, _] = a;
237     } else {
238         let[_, _y @ ..] = a;
239     }
240 }
241 
subslice_pattern_from_end_with_drop(a: &Allocator, arg: bool, arg2: bool)242 fn subslice_pattern_from_end_with_drop(a: &Allocator, arg: bool, arg2: bool) {
243     let a = [a.alloc(), a.alloc(), a.alloc(), a.alloc(), a.alloc()];
244     if arg2 {
245         drop(a);
246         return;
247     }
248 
249     if arg {
250         let[.., _x, _] = a;
251     } else {
252         let[_, _y @ ..] = a;
253     }
254 }
255 
slice_pattern_reassign(a: &Allocator)256 fn slice_pattern_reassign(a: &Allocator) {
257     let mut ar = [a.alloc(), a.alloc()];
258     let[_, _x] = ar;
259     ar = [a.alloc(), a.alloc()];
260     let[.., _y] = ar;
261 }
262 
subslice_pattern_reassign(a: &Allocator)263 fn subslice_pattern_reassign(a: &Allocator) {
264     let mut ar = [a.alloc(), a.alloc(), a.alloc()];
265     let[_, _, _x] = ar;
266     ar = [a.alloc(), a.alloc(), a.alloc()];
267     let[_, _y @ ..] = ar;
268 }
269 
index_field_mixed_ends(a: &Allocator)270 fn index_field_mixed_ends(a: &Allocator) {
271     let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())];
272     let[(_x, _), ..] = ar;
273     let[(_, _y), _] = ar;
274     let[_, (_, _w)] = ar;
275     let[.., (_z, _)] = ar;
276 }
277 
subslice_mixed_min_lengths(a: &Allocator, c: i32)278 fn subslice_mixed_min_lengths(a: &Allocator, c: i32) {
279     let ar = [(a.alloc(), a.alloc()), (a.alloc(), a.alloc())];
280     match c {
281         0 => { let[_x, ..] = ar; }
282         1 => { let[_x, _, ..] = ar; }
283         2 => { let[_x, _] = ar; }
284         3 => { let[(_x, _), _, ..] = ar; }
285         4 => { let[.., (_x, _)] = ar; }
286         5 => { let[.., (_x, _), _] = ar; }
287         6 => { let [_y @ ..] = ar; }
288         _ => { let [_y @ .., _] = ar; }
289     }
290 }
291 
bindings_after_at_dynamic_init_move(a: &Allocator, c: bool)292 fn bindings_after_at_dynamic_init_move(a: &Allocator, c: bool) {
293     let foo = if c { Some(a.alloc()) } else { None };
294     let _x;
295 
296     if let bar @ Some(_) = foo {
297         _x = bar;
298     }
299 }
300 
bindings_after_at_dynamic_init_ref(a: &Allocator, c: bool)301 fn bindings_after_at_dynamic_init_ref(a: &Allocator, c: bool) {
302     let foo = if c { Some(a.alloc()) } else { None };
303     let _x;
304 
305     if let bar @ Some(_baz) = &foo {
306         _x = bar;
307     }
308 }
309 
bindings_after_at_dynamic_drop_move(a: &Allocator, c: bool)310 fn bindings_after_at_dynamic_drop_move(a: &Allocator, c: bool) {
311     let foo = if c { Some(a.alloc()) } else { None };
312 
313     if let bar @ Some(_) = foo {
314         bar
315     } else {
316         None
317     };
318 }
319 
bindings_after_at_dynamic_drop_ref(a: &Allocator, c: bool)320 fn bindings_after_at_dynamic_drop_ref(a: &Allocator, c: bool) {
321     let foo = if c { Some(a.alloc()) } else { None };
322 
323     if let bar @ Some(_baz) = &foo {
324         bar
325     } else {
326         &None
327     };
328 }
329 
move_ref_pattern(a: &Allocator)330 fn move_ref_pattern(a: &Allocator) {
331     let mut tup = (a.alloc(), a.alloc(), a.alloc(), a.alloc());
332     let (ref _a, ref mut _b, _c, mut _d) = tup;
333 }
334 
panic_after_return(a: &Allocator) -> Ptr<'_>335 fn panic_after_return(a: &Allocator) -> Ptr<'_> {
336     // Panic in the drop of `p` or `q` can leak
337     let exceptions = vec![8, 9];
338     a.alloc();
339     let p = a.alloc();
340     {
341         a.alloc();
342         let p = a.alloc();
343         // FIXME (#47949) We leak values when we panic in a destructor after
344         // evaluating an expression with `rustc_mir::build::Builder::into`.
345         a.alloc_leaked(exceptions)
346     }
347 }
348 
panic_after_return_expr(a: &Allocator) -> Ptr<'_>349 fn panic_after_return_expr(a: &Allocator) -> Ptr<'_> {
350     // Panic in the drop of `p` or `q` can leak
351     let exceptions = vec![8, 9];
352     a.alloc();
353     let p = a.alloc();
354     {
355         a.alloc();
356         let q = a.alloc();
357         // FIXME (#47949)
358         return a.alloc_leaked(exceptions);
359     }
360 }
361 
panic_after_init(a: &Allocator)362 fn panic_after_init(a: &Allocator) {
363     // Panic in the drop of `r` can leak
364     let exceptions = vec![8];
365     a.alloc();
366     let p = a.alloc();
367     let q = {
368         a.alloc();
369         let r = a.alloc();
370         // FIXME (#47949)
371         a.alloc_leaked(exceptions)
372     };
373 }
374 
panic_after_init_temp(a: &Allocator)375 fn panic_after_init_temp(a: &Allocator) {
376     // Panic in the drop of `r` can leak
377     let exceptions = vec![8];
378     a.alloc();
379     let p = a.alloc();
380     {
381         a.alloc();
382         let r = a.alloc();
383         // FIXME (#47949)
384         a.alloc_leaked(exceptions)
385     };
386 }
387 
panic_after_init_by_loop(a: &Allocator)388 fn panic_after_init_by_loop(a: &Allocator) {
389     // Panic in the drop of `r` can leak
390     let exceptions = vec![8];
391     a.alloc();
392     let p = a.alloc();
393     let q = loop {
394         a.alloc();
395         let r = a.alloc();
396         // FIXME (#47949)
397         break a.alloc_leaked(exceptions);
398     };
399 }
400 
run_test<F>(mut f: F) where F: FnMut(&Allocator)401 fn run_test<F>(mut f: F)
402     where F: FnMut(&Allocator)
403 {
404     let first_alloc = Allocator::new(usize::MAX);
405     f(&first_alloc);
406 
407     for failing_op in 1..first_alloc.cur_ops.get()+1 {
408         let alloc = Allocator::new(failing_op);
409         let alloc = &alloc;
410         let f = panic::AssertUnwindSafe(&mut f);
411         let result = panic::catch_unwind(move || {
412             f.0(alloc);
413         });
414         match result {
415             Ok(..) => panic!("test executed {} ops but now {}",
416                              first_alloc.cur_ops.get(), alloc.cur_ops.get()),
417             Err(e) => {
418                 if e.downcast_ref::<InjectedFailure>().is_none() {
419                     panic::resume_unwind(e);
420                 }
421             }
422         }
423     }
424 }
425 
run_test_nopanic<F>(mut f: F) where F: FnMut(&Allocator)426 fn run_test_nopanic<F>(mut f: F)
427     where F: FnMut(&Allocator)
428 {
429     let first_alloc = Allocator::new(usize::MAX);
430     f(&first_alloc);
431 }
432 
main()433 fn main() {
434     run_test(|a| dynamic_init(a, false));
435     run_test(|a| dynamic_init(a, true));
436     run_test(|a| dynamic_drop(a, false));
437     run_test(|a| dynamic_drop(a, true));
438 
439     run_test(|a| assignment2(a, false, false));
440     run_test(|a| assignment2(a, false, true));
441     run_test(|a| assignment2(a, true, false));
442     run_test(|a| assignment2(a, true, true));
443 
444     run_test(|a| assignment1(a, false));
445     run_test(|a| assignment1(a, true));
446 
447     run_test(|a| array_simple(a));
448     run_test(|a| vec_simple(a));
449     run_test(|a| vec_unreachable(a));
450 
451     run_test(|a| struct_dynamic_drop(a, false, false, false));
452     run_test(|a| struct_dynamic_drop(a, false, false, true));
453     run_test(|a| struct_dynamic_drop(a, false, true, false));
454     run_test(|a| struct_dynamic_drop(a, false, true, true));
455     run_test(|a| struct_dynamic_drop(a, true, false, false));
456     run_test(|a| struct_dynamic_drop(a, true, false, true));
457     run_test(|a| struct_dynamic_drop(a, true, true, false));
458     run_test(|a| struct_dynamic_drop(a, true, true, true));
459 
460     run_test(|a| field_assignment(a, false));
461     run_test(|a| field_assignment(a, true));
462 
463     run_test(|a| generator(a, 0));
464     run_test(|a| generator(a, 1));
465     run_test(|a| generator(a, 2));
466     run_test(|a| generator(a, 3));
467 
468     run_test(|a| mixed_drop_and_nondrop(a));
469 
470     run_test(|a| slice_pattern_first(a));
471     run_test(|a| slice_pattern_middle(a));
472     run_test(|a| slice_pattern_two(a));
473     run_test(|a| slice_pattern_last(a));
474     run_test(|a| slice_pattern_one_of(a, 0));
475     run_test(|a| slice_pattern_one_of(a, 1));
476     run_test(|a| slice_pattern_one_of(a, 2));
477     run_test(|a| slice_pattern_one_of(a, 3));
478 
479     run_test(|a| subslice_pattern_from_end(a, true));
480     run_test(|a| subslice_pattern_from_end(a, false));
481     run_test(|a| subslice_pattern_from_end_with_drop(a, true, true));
482     run_test(|a| subslice_pattern_from_end_with_drop(a, true, false));
483     run_test(|a| subslice_pattern_from_end_with_drop(a, false, true));
484     run_test(|a| subslice_pattern_from_end_with_drop(a, false, false));
485     run_test(|a| slice_pattern_reassign(a));
486     run_test(|a| subslice_pattern_reassign(a));
487 
488     run_test(|a| index_field_mixed_ends(a));
489     run_test(|a| subslice_mixed_min_lengths(a, 0));
490     run_test(|a| subslice_mixed_min_lengths(a, 1));
491     run_test(|a| subslice_mixed_min_lengths(a, 2));
492     run_test(|a| subslice_mixed_min_lengths(a, 3));
493     run_test(|a| subslice_mixed_min_lengths(a, 4));
494     run_test(|a| subslice_mixed_min_lengths(a, 5));
495     run_test(|a| subslice_mixed_min_lengths(a, 6));
496     run_test(|a| subslice_mixed_min_lengths(a, 7));
497 
498     run_test(|a| move_ref_pattern(a));
499 
500     run_test(|a| {
501         panic_after_return(a);
502     });
503     run_test(|a| {
504         panic_after_return_expr(a);
505     });
506     run_test(|a| panic_after_init(a));
507     run_test(|a| panic_after_init_temp(a));
508     run_test(|a| panic_after_init_by_loop(a));
509 
510     run_test(|a| bindings_after_at_dynamic_init_move(a, true));
511     run_test(|a| bindings_after_at_dynamic_init_move(a, false));
512     run_test(|a| bindings_after_at_dynamic_init_ref(a, true));
513     run_test(|a| bindings_after_at_dynamic_init_ref(a, false));
514     run_test(|a| bindings_after_at_dynamic_drop_move(a, true));
515     run_test(|a| bindings_after_at_dynamic_drop_move(a, false));
516     run_test(|a| bindings_after_at_dynamic_drop_ref(a, true));
517     run_test(|a| bindings_after_at_dynamic_drop_ref(a, false));
518 
519     run_test_nopanic(|a| union1(a));
520 }
521