Skip to content

Commit e075ff3

Browse files
crepererumtaiki-e
authored andcommitted
Shared: fix false detection of inner panics (#2576)
Fixes #2575.
1 parent 8ace968 commit e075ff3

File tree

2 files changed

+45
-9
lines changed

2 files changed

+45
-9
lines changed

futures-util/src/future/future/shared.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -262,19 +262,20 @@ where
262262
let waker = waker_ref(&inner.notifier);
263263
let mut cx = Context::from_waker(&waker);
264264

265-
struct Reset<'a>(&'a AtomicUsize);
265+
struct Reset<'a> {
266+
state: &'a AtomicUsize,
267+
did_not_panic: bool,
268+
}
266269

267270
impl Drop for Reset<'_> {
268271
fn drop(&mut self) {
269-
use std::thread;
270-
271-
if thread::panicking() {
272-
self.0.store(POISONED, SeqCst);
272+
if !self.did_not_panic {
273+
self.state.store(POISONED, SeqCst);
273274
}
274275
}
275276
}
276277

277-
let _reset = Reset(&inner.notifier.state);
278+
let mut reset = Reset { state: &inner.notifier.state, did_not_panic: false };
278279

279280
let output = {
280281
let future = unsafe {
@@ -284,12 +285,15 @@ where
284285
}
285286
};
286287

287-
match future.poll(&mut cx) {
288+
let poll_result = future.poll(&mut cx);
289+
reset.did_not_panic = true;
290+
291+
match poll_result {
288292
Poll::Pending => {
289293
if inner.notifier.state.compare_exchange(POLLING, IDLE, SeqCst, SeqCst).is_ok()
290294
{
291295
// Success
292-
drop(_reset);
296+
drop(reset);
293297
this.inner = Some(inner);
294298
return Poll::Pending;
295299
} else {
@@ -313,7 +317,7 @@ where
313317
waker.wake();
314318
}
315319

316-
drop(_reset); // Make borrow checker happy
320+
drop(reset); // Make borrow checker happy
317321
drop(wakers_guard);
318322

319323
// Safety: We're in the COMPLETE state

futures/tests/future_shared.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use futures::executor::{block_on, LocalPool};
33
use futures::future::{self, FutureExt, LocalFutureObj, TryFutureExt};
44
use futures::task::LocalSpawn;
55
use std::cell::{Cell, RefCell};
6+
use std::panic::AssertUnwindSafe;
67
use std::rc::Rc;
78
use std::task::Poll;
89
use std::thread;
@@ -194,3 +195,34 @@ fn shared_future_that_wakes_itself_until_pending_is_returned() {
194195
// has returned pending
195196
assert_eq!(block_on(futures::future::join(fut, async { proceed.set(true) })), ((), ()));
196197
}
198+
199+
#[test]
200+
#[should_panic(expected = "inner future panicked during poll")]
201+
fn panic_while_poll() {
202+
let fut = futures::future::poll_fn::<i8, _>(|_cx| panic!("test")).shared();
203+
204+
let fut_captured = fut.clone();
205+
std::panic::catch_unwind(AssertUnwindSafe(|| {
206+
block_on(fut_captured);
207+
}))
208+
.unwrap_err();
209+
210+
block_on(fut);
211+
}
212+
213+
#[test]
214+
#[should_panic(expected = "test_marker")]
215+
fn poll_while_panic() {
216+
struct S;
217+
218+
impl Drop for S {
219+
fn drop(&mut self) {
220+
let fut = futures::future::ready(1).shared();
221+
assert_eq!(block_on(fut.clone()), 1);
222+
assert_eq!(block_on(fut), 1);
223+
}
224+
}
225+
226+
let _s = S {};
227+
panic!("test_marker");
228+
}

0 commit comments

Comments
 (0)