1 // Test that values are not leaked in async functions, even in the cases where:
2 // * Dropping one of the values panics while running the future.
3 // * The future is dropped at one of its suspend points.
4 // * Dropping one of the values panics while dropping the future.
8 // ignore-wasm32-bare compiled with panic=abort by default
13 cell
::{Cell, RefCell}
,
20 task
::{Context, Poll, RawWaker, RawWakerVTable, Waker}
,
23 struct InjectedFailure
;
30 impl<T
: Unpin
> Future
for Defer
<T
> {
32 fn poll(mut self: Pin
<&mut Self>, cx
: &mut Context
) -> Poll
<Self::Output
> {
34 Poll
::Ready(self.value
.take().unwrap())
42 /// Allocator tracks the creation and destruction of `Ptr`s.
43 /// The `failing_op`-th operation will panic.
45 data
: RefCell
<Vec
<bool
>>,
50 impl panic
::UnwindSafe
for Allocator {}
51 impl panic
::RefUnwindSafe
for Allocator {}
53 impl Drop
for Allocator
{
55 let data
= self.data
.borrow();
56 if data
.iter().any(|d
| *d
) {
57 panic
!("missing free: {:?}", data
);
63 fn new(failing_op
: usize) -> Self {
64 Allocator { failing_op, cur_ops: Cell::new(0), data: RefCell::new(vec![]) }
66 fn alloc(&self) -> impl Future
<Output
= Ptr
<'_
>> + '_
{
67 self.fallible_operation();
69 let mut data
= self.data
.borrow_mut();
71 let addr
= data
.len();
73 Defer { ready: false, value: Some(Ptr(addr, self)) }
75 fn fallible_operation(&self) {
76 self.cur_ops
.set(self.cur_ops
.get() + 1);
78 if self.cur_ops
.get() == self.failing_op
{
79 panic
!(InjectedFailure
);
84 // Type that tracks whether it was dropped and can panic when it's created or
86 struct Ptr
<'a
>(usize, &'a Allocator
);
87 impl<'a
> Drop
for Ptr
<'a
> {
89 match self.1.data
.borrow_mut()[self.0] {
90 false => panic
!("double free at index {:?}", self.0),
91 ref mut d
=> *d
= false,
94 self.1.fallible_operation
();
98 async
fn dynamic_init(a
: Rc
<Allocator
>, c
: bool
) {
101 _x
= Some(a
.alloc().await
);
105 async
fn dynamic_drop(a
: Rc
<Allocator
>, c
: bool
) {
106 let x
= a
.alloc().await
;
114 struct TwoPtrs
<'a
>(Ptr
<'a
>, Ptr
<'a
>);
115 async
fn struct_dynamic_drop(a
: Rc
<Allocator
>, c0
: bool
, c1
: bool
, c
: bool
) {
119 if (c0
&& i
== 0) || (c1
&& i
== 1) {
120 x
= (a
.alloc().await
, a
.alloc().await
, a
.alloc().await
);
121 y
= TwoPtrs(a
.alloc().await
, a
.alloc().await
);
132 async
fn field_assignment(a
: Rc
<Allocator
>, c0
: bool
) {
133 let mut x
= (TwoPtrs(a
.alloc().await
, a
.alloc().await
), a
.alloc().await
);
135 x
.1 = a
.alloc().await
;
136 x
.1 = a
.alloc().await
;
146 async
fn assignment(a
: Rc
<Allocator
>, c0
: bool
, c1
: bool
) {
147 let mut _v
= a
.alloc().await
;
148 let mut _w
= a
.alloc().await
;
154 _w
= a
.alloc().await
;
158 async
fn array_simple(a
: Rc
<Allocator
>) {
159 let _x
= [a
.alloc().await
, a
.alloc().await
, a
.alloc().await
, a
.alloc().await
];
162 async
fn vec_simple(a
: Rc
<Allocator
>) {
163 let _x
= vec
![a
.alloc().await
, a
.alloc().await
, a
.alloc().await
, a
.alloc().await
];
166 async
fn mixed_drop_and_nondrop(a
: Rc
<Allocator
>) {
167 // check that destructor panics handle drop
168 // and non-drop blocks in the same scope correctly.
170 // Surprisingly enough, this used to not work.
177 #[allow(unreachable_code)]
178 async
fn vec_unreachable(a
: Rc
<Allocator
>) {
179 let _x
= vec
![a
.alloc().await
, a
.alloc().await
, a
.alloc().await
, return];
182 async
fn slice_pattern_one_of(a
: Rc
<Allocator
>, i
: usize) {
183 let array
= [a
.alloc().await
, a
.alloc().await
, a
.alloc().await
, a
.alloc().await
];
190 let [_
, a
, ..] = array
;
194 let [_
, _
, a
, _
] = array
;
198 let [_
, _
, _
, a
] = array
;
201 _
=> panic
!("unmatched"),
206 async
fn subslice_pattern_from_end_with_drop(a
: Rc
<Allocator
>, arg
: bool
, arg2
: bool
) {
207 let arr
= [a
.alloc().await
, a
.alloc().await
, a
.alloc().await
, a
.alloc().await
, a
.alloc().await
];
214 let [.., _x
, _
] = arr
;
216 let [_
, _y @
..] = arr
;
221 async
fn subslice_pattern_reassign(a
: Rc
<Allocator
>) {
222 let mut ar
= [a
.alloc().await
, a
.alloc().await
, a
.alloc().await
];
224 ar
= [a
.alloc().await
, a
.alloc().await
, a
.alloc().await
];
225 let [_
, _y @
..] = ar
;
229 async
fn move_ref_pattern(a
: Rc
<Allocator
>) {
230 let mut tup
= (a
.alloc().await
, a
.alloc().await
, a
.alloc().await
, a
.alloc().await
);
231 let (ref _a
, ref mut _b
, _c
, mut _d
) = tup
;
235 fn run_test
<F
, G
>(cx
: &mut Context
<'_
>, ref f
: F
)
237 F
: Fn(Rc
<Allocator
>) -> G
,
238 G
: Future
<Output
= ()>,
241 // Run without any panics to find which operations happen after the
242 // penultimate `poll`.
243 let first_alloc
= Rc
::new(Allocator
::new(usize::MAX
));
244 let mut fut
= Box
::pin(f(first_alloc
.clone()));
245 let mut ops_before_last_poll
= 0;
246 let mut completed
= false;
248 ops_before_last_poll
= first_alloc
.cur_ops
.get();
249 if let Poll
::Ready(()) = fut
.as_mut().poll(cx
) {
255 // Start at `ops_before_last_poll` so that we will always be able to
256 // `poll` the expected number of times.
257 for failing_op
in ops_before_last_poll
..first_alloc
.cur_ops
.get() {
258 let alloc
= Rc
::new(Allocator
::new(failing_op
+ 1));
261 let result
= panic
::catch_unwind(panic
::AssertUnwindSafe(move || {
262 let mut fut
= Box
::pin(f(alloc
));
264 let _
= fut
.as_mut().poll(cx
);
269 Ok(..) => panic
!("test executed more ops on first call"),
271 if e
.downcast_ref
::<InjectedFailure
>().is_none() {
272 panic
::resume_unwind(e
);
284 fn clone_waker(data
: *const ()) -> RawWaker
{
285 RawWaker
::new(data
, &RawWakerVTable
::new(clone_waker
, drop
, drop
, drop
))
289 let waker
= unsafe { Waker::from_raw(clone_waker(ptr::null())) }
;
290 let context
= &mut Context
::from_waker(&waker
);
292 run_test(context
, |a
| dynamic_init(a
, false));
293 run_test(context
, |a
| dynamic_init(a
, true));
294 run_test(context
, |a
| dynamic_drop(a
, false));
295 run_test(context
, |a
| dynamic_drop(a
, true));
297 run_test(context
, |a
| assignment(a
, false, false));
298 run_test(context
, |a
| assignment(a
, false, true));
299 run_test(context
, |a
| assignment(a
, true, false));
300 run_test(context
, |a
| assignment(a
, true, true));
302 run_test(context
, |a
| array_simple(a
));
303 run_test(context
, |a
| vec_simple(a
));
304 run_test(context
, |a
| vec_unreachable(a
));
306 run_test(context
, |a
| struct_dynamic_drop(a
, false, false, false));
307 run_test(context
, |a
| struct_dynamic_drop(a
, false, false, true));
308 run_test(context
, |a
| struct_dynamic_drop(a
, false, true, false));
309 run_test(context
, |a
| struct_dynamic_drop(a
, false, true, true));
310 run_test(context
, |a
| struct_dynamic_drop(a
, true, false, false));
311 run_test(context
, |a
| struct_dynamic_drop(a
, true, false, true));
312 run_test(context
, |a
| struct_dynamic_drop(a
, true, true, false));
313 run_test(context
, |a
| struct_dynamic_drop(a
, true, true, true));
315 run_test(context
, |a
| field_assignment(a
, false));
316 run_test(context
, |a
| field_assignment(a
, true));
318 run_test(context
, |a
| mixed_drop_and_nondrop(a
));
320 run_test(context
, |a
| slice_pattern_one_of(a
, 0));
321 run_test(context
, |a
| slice_pattern_one_of(a
, 1));
322 run_test(context
, |a
| slice_pattern_one_of(a
, 2));
323 run_test(context
, |a
| slice_pattern_one_of(a
, 3));
325 run_test(context
, |a
| subslice_pattern_from_end_with_drop(a
, true, true));
326 run_test(context
, |a
| subslice_pattern_from_end_with_drop(a
, true, false));
327 run_test(context
, |a
| subslice_pattern_from_end_with_drop(a
, false, true));
328 run_test(context
, |a
| subslice_pattern_from_end_with_drop(a
, false, false));
329 run_test(context
, |a
| subslice_pattern_reassign(a
));
331 run_test(context
, |a
| move_ref_pattern(a
));