Skip to content

Commit 8479bd2

Browse files
Thomasdezeeuwcramertj
authored andcommitted
Don't panic in AssertUnmoved while panicking
Also doesn't panic anymore if the future was never polled and then dropped. Fixes #1394.
1 parent f67f6f3 commit 8479bd2

File tree

1 file changed

+44
-2
lines changed

1 file changed

+44
-2
lines changed

futures-test/src/future/assert_unmoved.rs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use pin_utils::{unsafe_pinned, unsafe_unpinned};
44
use std::marker::PhantomPinned;
55
use std::pin::Pin;
66
use std::ptr;
7+
use std::thread::panicking;
78

89
/// Combinator for the
910
/// [`FutureTestExt::assert_unmoved`](super::FutureTestExt::assert_unmoved)
@@ -49,7 +50,48 @@ impl<Fut: Future> Future for AssertUnmoved<Fut> {
4950

5051
impl<Fut> Drop for AssertUnmoved<Fut> {
5152
fn drop(&mut self) {
52-
let cur_this = &*self as *const Self;
53-
assert_eq!(self.this_ptr, cur_this, "Future moved before drop");
53+
// If the thread is panicking then we can't panic again as that will
54+
// cause the process to be aborted.
55+
if !panicking() && !self.this_ptr.is_null() {
56+
let cur_this = &*self as *const Self;
57+
assert_eq!(self.this_ptr, cur_this, "Future moved before drop");
58+
}
59+
}
60+
}
61+
62+
#[cfg(test)]
63+
mod tests {
64+
use futures_core::future::Future;
65+
use futures_core::task::Poll;
66+
use futures_util::future::empty;
67+
use futures_util::task::noop_local_waker;
68+
use std::pin::Pin;
69+
70+
use super::AssertUnmoved;
71+
72+
#[test]
73+
fn dont_panic_when_not_polled() {
74+
// This shouldn't panic.
75+
let future = AssertUnmoved::new(empty::<()>());
76+
drop(future);
77+
}
78+
79+
#[test]
80+
#[should_panic(expected = "Future moved between poll calls")]
81+
fn dont_double_panic() {
82+
// This test should only panic, not abort the process.
83+
let waker = noop_local_waker();
84+
85+
// First we allocate the future on the stack and poll it.
86+
let mut future = AssertUnmoved::new(empty::<()>());
87+
let pinned_future = unsafe { Pin::new_unchecked(&mut future) };
88+
assert_eq!(pinned_future.poll(&waker), Poll::Pending);
89+
90+
// Next we move it back to the heap and poll it again. This second call
91+
// should panic (as the future is moved), but we shouldn't panic again
92+
// whilst dropping `AssertUnmoved`.
93+
let mut future = Box::new(future);
94+
let pinned_boxed_future = unsafe { Pin::new_unchecked(&mut *future) };
95+
assert_eq!(pinned_boxed_future.poll(&waker), Poll::Pending);
5496
}
5597
}

0 commit comments

Comments
 (0)