Skip to content

Commit 4f4b032

Browse files
committed
Add 'static bound to waker_ref
1 parent 42c2ab0 commit 4f4b032

File tree

4 files changed

+101
-11
lines changed

4 files changed

+101
-11
lines changed

futures-task/src/waker.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use alloc::sync::Arc;
33
use core::mem;
44
use core::task::{RawWaker, RawWakerVTable, Waker};
55

6-
pub(super) fn waker_vtable<W: ArcWake>() -> &'static RawWakerVTable {
6+
pub(super) fn waker_vtable<W: ArcWake + 'static>() -> &'static RawWakerVTable {
77
&RawWakerVTable::new(
88
clone_arc_raw::<W>,
99
wake_arc_raw::<W>,
@@ -28,31 +28,31 @@ where
2828
// FIXME: panics on Arc::clone / refcount changes could wreak havoc on the
2929
// code here. We should guard against this by aborting.
3030

31-
unsafe fn increase_refcount<T: ArcWake>(data: *const ()) {
31+
unsafe fn increase_refcount<T: ArcWake + 'static>(data: *const ()) {
3232
// Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
3333
let arc = mem::ManuallyDrop::new(unsafe { Arc::<T>::from_raw(data.cast::<T>()) });
3434
// Now increase refcount, but don't drop new refcount either
3535
let _arc_clone: mem::ManuallyDrop<_> = arc.clone();
3636
}
3737

3838
// used by `waker_ref`
39-
unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker {
39+
unsafe fn clone_arc_raw<T: ArcWake + 'static>(data: *const ()) -> RawWaker {
4040
unsafe { increase_refcount::<T>(data) }
4141
RawWaker::new(data, waker_vtable::<T>())
4242
}
4343

44-
unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) {
44+
unsafe fn wake_arc_raw<T: ArcWake + 'static>(data: *const ()) {
4545
let arc: Arc<T> = unsafe { Arc::from_raw(data.cast::<T>()) };
4646
ArcWake::wake(arc);
4747
}
4848

4949
// used by `waker_ref`
50-
unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) {
50+
unsafe fn wake_by_ref_arc_raw<T: ArcWake + 'static>(data: *const ()) {
5151
// Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
5252
let arc = mem::ManuallyDrop::new(unsafe { Arc::<T>::from_raw(data.cast::<T>()) });
5353
ArcWake::wake_by_ref(&arc);
5454
}
5555

56-
unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) {
56+
unsafe fn drop_arc_raw<T: ArcWake + 'static>(data: *const ()) {
5757
drop(unsafe { Arc::<T>::from_raw(data.cast::<T>()) })
5858
}

futures-task/src/waker_ref.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ impl Deref for WakerRef<'_> {
5454
#[inline]
5555
pub fn waker_ref<W>(wake: &Arc<W>) -> WakerRef<'_>
5656
where
57-
W: ArcWake,
57+
W: ArcWake + 'static,
5858
{
5959
// simply copy the pointer instead of using Arc::into_raw,
6060
// as we don't actually keep a refcount by using ManuallyDrop.<

futures-util/src/stream/futures_unordered/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,8 @@ impl<Fut: Future> Stream for FuturesUnordered<Fut> {
510510
// We are only interested in whether the future is awoken before it
511511
// finishes polling, so reset the flag here.
512512
task.woken.store(false, Relaxed);
513-
let waker = Task::waker_ref(task);
513+
// SAFETY: see the comments of Bomb and this block.
514+
let waker = unsafe { Task::waker_ref(task) };
514515
let mut cx = Context::from_waker(&waker);
515516

516517
// Safety: We won't move the future ever again

futures-util/src/stream/futures_unordered/task.rs

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use core::sync::atomic::{AtomicBool, AtomicPtr};
55

66
use super::abort::abort;
77
use super::ReadyToRunQueue;
8-
use crate::task::{waker_ref, ArcWake, WakerRef};
8+
use crate::task::ArcWake;
99

1010
pub(super) struct Task<Fut> {
1111
// The future
@@ -77,8 +77,8 @@ impl<Fut> ArcWake for Task<Fut> {
7777

7878
impl<Fut> Task<Fut> {
7979
/// Returns a waker reference for this task without cloning the Arc.
80-
pub(super) fn waker_ref(this: &Arc<Self>) -> WakerRef<'_> {
81-
waker_ref(this)
80+
pub(super) unsafe fn waker_ref(this: &Arc<Self>) -> waker_ref::WakerRef<'_> {
81+
unsafe { waker_ref::waker_ref(this) }
8282
}
8383

8484
/// Spins until `next_all` is no longer set to `pending_next_all`.
@@ -123,3 +123,92 @@ impl<Fut> Drop for Task<Fut> {
123123
}
124124
}
125125
}
126+
127+
mod waker_ref {
128+
use alloc::sync::Arc;
129+
use core::marker::PhantomData;
130+
use core::mem;
131+
use core::mem::ManuallyDrop;
132+
use core::ops::Deref;
133+
use core::task::{RawWaker, RawWakerVTable, Waker};
134+
use futures_task::ArcWake;
135+
136+
pub(crate) struct WakerRef<'a> {
137+
waker: ManuallyDrop<Waker>,
138+
_marker: PhantomData<&'a ()>,
139+
}
140+
141+
impl WakerRef<'_> {
142+
#[inline]
143+
fn new_unowned(waker: ManuallyDrop<Waker>) -> Self {
144+
Self { waker, _marker: PhantomData }
145+
}
146+
}
147+
148+
impl Deref for WakerRef<'_> {
149+
type Target = Waker;
150+
151+
#[inline]
152+
fn deref(&self) -> &Waker {
153+
&self.waker
154+
}
155+
}
156+
157+
/// Copy of `future_task::waker_ref` without `W: 'static` bound.
158+
///
159+
/// # Safety
160+
///
161+
/// The caller must guarantee that use-after-free will not occur.
162+
#[inline]
163+
pub(crate) unsafe fn waker_ref<W>(wake: &Arc<W>) -> WakerRef<'_>
164+
where
165+
W: ArcWake,
166+
{
167+
// simply copy the pointer instead of using Arc::into_raw,
168+
// as we don't actually keep a refcount by using ManuallyDrop.<
169+
let ptr = Arc::as_ptr(wake).cast::<()>();
170+
171+
let waker =
172+
ManuallyDrop::new(unsafe { Waker::from_raw(RawWaker::new(ptr, waker_vtable::<W>())) });
173+
WakerRef::new_unowned(waker)
174+
}
175+
176+
fn waker_vtable<W: ArcWake>() -> &'static RawWakerVTable {
177+
&RawWakerVTable::new(
178+
clone_arc_raw::<W>,
179+
wake_arc_raw::<W>,
180+
wake_by_ref_arc_raw::<W>,
181+
drop_arc_raw::<W>,
182+
)
183+
}
184+
185+
// FIXME: panics on Arc::clone / refcount changes could wreak havoc on the
186+
// code here. We should guard against this by aborting.
187+
188+
unsafe fn increase_refcount<T: ArcWake>(data: *const ()) {
189+
// Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
190+
let arc = mem::ManuallyDrop::new(unsafe { Arc::<T>::from_raw(data.cast::<T>()) });
191+
// Now increase refcount, but don't drop new refcount either
192+
let _arc_clone: mem::ManuallyDrop<_> = arc.clone();
193+
}
194+
195+
unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker {
196+
unsafe { increase_refcount::<T>(data) }
197+
RawWaker::new(data, waker_vtable::<T>())
198+
}
199+
200+
unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) {
201+
let arc: Arc<T> = unsafe { Arc::from_raw(data.cast::<T>()) };
202+
ArcWake::wake(arc);
203+
}
204+
205+
unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) {
206+
// Retain Arc, but don't touch refcount by wrapping in ManuallyDrop
207+
let arc = mem::ManuallyDrop::new(unsafe { Arc::<T>::from_raw(data.cast::<T>()) });
208+
ArcWake::wake_by_ref(&arc);
209+
}
210+
211+
unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) {
212+
drop(unsafe { Arc::<T>::from_raw(data.cast::<T>()) })
213+
}
214+
}

0 commit comments

Comments
 (0)