Skip to content

Commit 5a6b1b3

Browse files
Nemo157cramertj
authored andcommitted
Change FutureObj to use a *mut dyn Future fat pointer
1 parent 0a2d040 commit 5a6b1b3

File tree

3 files changed

+151
-68
lines changed

3 files changed

+151
-68
lines changed

futures-core/src/future/future_obj.rs

Lines changed: 146 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use core::{
2+
mem,
23
fmt,
34
future::Future,
45
marker::PhantomData,
@@ -13,22 +14,33 @@ use core::{
1314
/// take `dyn Trait` by value and `Box<dyn Trait>` is not available in no_std
1415
/// contexts.
1516
pub struct LocalFutureObj<'a, T> {
16-
ptr: *mut (),
17-
poll_fn: unsafe fn(*mut (), &mut Context<'_>) -> Poll<T>,
18-
drop_fn: unsafe fn(*mut ()),
17+
future: *mut (dyn Future<Output = T> + 'static),
18+
drop_fn: unsafe fn(*mut (dyn Future<Output = T> + 'static)),
1919
_marker: PhantomData<&'a ()>,
2020
}
2121

2222
impl<T> Unpin for LocalFutureObj<'_, T> {}
2323

24+
#[allow(clippy::transmute_ptr_to_ptr)]
25+
unsafe fn remove_future_lifetime<'a, T>(ptr: *mut (dyn Future<Output = T> + 'a))
26+
-> *mut (dyn Future<Output = T> + 'static)
27+
{
28+
mem::transmute(ptr)
29+
}
30+
31+
unsafe fn remove_drop_lifetime<'a, T>(ptr: unsafe fn (*mut (dyn Future<Output = T> + 'a)))
32+
-> unsafe fn(*mut (dyn Future<Output = T> + 'static))
33+
{
34+
mem::transmute(ptr)
35+
}
36+
2437
impl<'a, T> LocalFutureObj<'a, T> {
2538
/// Create a `LocalFutureObj` from a custom trait object representation.
2639
#[inline]
2740
pub fn new<F: UnsafeFutureObj<'a, T> + 'a>(f: F) -> LocalFutureObj<'a, T> {
2841
LocalFutureObj {
29-
ptr: f.into_raw(),
30-
poll_fn: F::poll,
31-
drop_fn: F::drop,
42+
future: unsafe { remove_future_lifetime(f.into_raw()) },
43+
drop_fn: unsafe { remove_drop_lifetime(F::drop) },
3244
_marker: PhantomData,
3345
}
3446
}
@@ -61,17 +73,17 @@ impl<T> Future for LocalFutureObj<'_, T> {
6173
type Output = T;
6274

6375
#[inline]
64-
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
76+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
6577
unsafe {
66-
((*self).poll_fn)((*self).ptr, cx)
78+
Pin::new_unchecked(&mut *self.future).poll(cx)
6779
}
6880
}
6981
}
7082

7183
impl<T> Drop for LocalFutureObj<'_, T> {
7284
fn drop(&mut self) {
7385
unsafe {
74-
(self.drop_fn)(self.ptr)
86+
(self.drop_fn)(self.future)
7587
}
7688
}
7789
}
@@ -119,115 +131,174 @@ impl<T> Future for FutureObj<'_, T> {
119131
}
120132

121133
/// A custom implementation of a future trait object for `FutureObj`, providing
122-
/// a hand-rolled vtable.
134+
/// a vtable with drop support.
123135
///
124136
/// This custom representation is typically used only in `no_std` contexts,
125137
/// where the default `Box`-based implementation is not available.
126138
///
127-
/// The implementor must guarantee that it is safe to call `poll` repeatedly (in
128-
/// a non-concurrent fashion) with the result of `into_raw` until `drop` is
129-
/// called.
139+
/// # Safety
140+
///
141+
/// See the safety notes on individual methods for what guarantees an
142+
/// implementor must provide.
130143
pub unsafe trait UnsafeFutureObj<'a, T>: 'a {
131-
/// Convert an owned instance into a (conceptually owned) void pointer.
132-
fn into_raw(self) -> *mut ();
133-
134-
/// Poll the future represented by the given void pointer.
144+
/// Convert an owned instance into a (conceptually owned) fat pointer.
135145
///
136146
/// # Safety
137147
///
138-
/// The trait implementor must guarantee that it is safe to repeatedly call
139-
/// `poll` with the result of `into_raw` until `drop` is called; such calls
140-
/// are not, however, allowed to race with each other or with calls to
141-
/// `drop`.
142-
unsafe fn poll(ptr: *mut (), cx: &mut Context<'_>) -> Poll<T>;
148+
/// ## Implementor
149+
///
150+
/// The trait implementor must guarantee that it is safe to convert the
151+
/// provided `*mut (dyn Future<Output = T> + 'a)` into a `Pin<&mut (dyn
152+
/// Future<Output = T> + 'a)>` and call methods on it, non-reentrantly,
153+
/// until `UnsafeFutureObj::drop` is called with it.
154+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a);
143155

144-
/// Drops the future represented by the given void pointer.
156+
/// Drops the future represented by the given fat pointer.
145157
///
146158
/// # Safety
147159
///
160+
/// ## Implementor
161+
///
148162
/// The trait implementor must guarantee that it is safe to call this
149-
/// function once per `into_raw` invocation; that call cannot race with
150-
/// other calls to `drop` or `poll`.
151-
unsafe fn drop(ptr: *mut ());
163+
/// function once per `into_raw` invocation.
164+
///
165+
/// ## Caller
166+
///
167+
/// The caller must ensure:
168+
///
169+
/// * the pointer passed was obtained from an `into_raw` invocation from
170+
/// this same trait object
171+
/// * the pointer is not currently in use as a `Pin<&mut (dyn Future<Output
172+
/// = T> + 'a)>`
173+
/// * the pointer must not be used again after this function is called
174+
unsafe fn drop(ptr: *mut (dyn Future<Output = T> + 'a));
152175
}
153176

154177
unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for &'a mut F
155178
where
156179
F: Future<Output = T> + Unpin + 'a
157180
{
158-
fn into_raw(self) -> *mut () {
159-
self as *mut F as *mut ()
181+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
182+
self as *mut dyn Future<Output = T>
160183
}
161184

162-
unsafe fn poll(ptr: *mut (), cx: &mut Context<'_>) -> Poll<T> {
163-
let p: Pin<&mut F> = Pin::new_unchecked(&mut *(ptr as *mut F));
164-
F::poll(p, cx)
185+
unsafe fn drop(_ptr: *mut (dyn Future<Output = T> + 'a)) {}
186+
}
187+
188+
unsafe impl<'a, T> UnsafeFutureObj<'a, T> for &'a mut (dyn Future<Output = T> + Unpin + 'a)
189+
{
190+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
191+
self as *mut dyn Future<Output = T>
165192
}
166193

167-
unsafe fn drop(_ptr: *mut ()) {}
194+
unsafe fn drop(_ptr: *mut (dyn Future<Output = T> + 'a)) {}
168195
}
169196

170197
unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for Pin<&'a mut F>
171198
where
172199
F: Future<Output = T> + 'a
173200
{
174-
fn into_raw(mut self) -> *mut () {
175-
let mut_ref: &mut F = unsafe { Pin::get_unchecked_mut(self.as_mut()) };
176-
mut_ref as *mut F as *mut ()
201+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
202+
unsafe { self.get_unchecked_mut() as *mut dyn Future<Output = T> }
177203
}
178204

179-
unsafe fn poll(ptr: *mut (), cx: &mut Context<'_>) -> Poll<T> {
180-
let future: Pin<&mut F> = Pin::new_unchecked(&mut *(ptr as *mut F));
181-
F::poll(future, cx)
205+
unsafe fn drop(_ptr: *mut (dyn Future<Output = T> + 'a)) {}
206+
}
207+
208+
unsafe impl<'a, T> UnsafeFutureObj<'a, T> for Pin<&'a mut (dyn Future<Output = T> + 'a)>
209+
{
210+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
211+
unsafe { self.get_unchecked_mut() as *mut dyn Future<Output = T> }
182212
}
183213

184-
unsafe fn drop(_ptr: *mut ()) {}
214+
unsafe fn drop(_ptr: *mut (dyn Future<Output = T> + 'a)) {}
185215
}
186216

187217
#[cfg(feature = "alloc")]
188218
mod if_alloc {
189219
use super::*;
190-
use core::mem;
191220
use alloc::boxed::Box;
192221

193222
unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for Box<F>
194223
where F: Future<Output = T> + 'a
195224
{
196-
fn into_raw(self) -> *mut () {
197-
Box::into_raw(self) as *mut ()
225+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
226+
Box::into_raw(self)
198227
}
199228

200-
unsafe fn poll(ptr: *mut (), cx: &mut Context<'_>) -> Poll<T> {
201-
let ptr = ptr as *mut F;
202-
let pin: Pin<&mut F> = Pin::new_unchecked(&mut *ptr);
203-
F::poll(pin, cx)
229+
unsafe fn drop(ptr: *mut (dyn Future<Output = T> + 'a)) {
230+
drop(Box::from_raw(ptr as *mut F))
204231
}
232+
}
205233

206-
unsafe fn drop(ptr: *mut ()) {
207-
drop(Box::from_raw(ptr as *mut F))
234+
unsafe impl<'a, T: 'a> UnsafeFutureObj<'a, T> for Box<dyn Future<Output = T> + 'a> {
235+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
236+
Box::into_raw(self)
237+
}
238+
239+
unsafe fn drop(ptr: *mut (dyn Future<Output = T> + 'a)) {
240+
drop(Box::from_raw(ptr))
241+
}
242+
}
243+
244+
unsafe impl<'a, T: 'a> UnsafeFutureObj<'a, T> for Box<dyn Future<Output = T> + Send + 'a> {
245+
fn into_raw(self) -> *mut (dyn Future<Output = T> + 'a) {
246+
Box::into_raw(self)
247+
}
248+
249+
unsafe fn drop(ptr: *mut (dyn Future<Output = T> + 'a)) {
250+
drop(Box::from_raw(ptr))
208251
}
209252
}
210253

211254
unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for Pin<Box<F>>
212255
where
213256
F: Future<Output = T> + 'a
214257
{
215-
fn into_raw(mut self) -> *mut () {
216-
let mut_ref: &mut F = unsafe { Pin::get_unchecked_mut(self.as_mut()) };
217-
let ptr = mut_ref as *mut F as *mut ();
218-
mem::forget(self); // Don't drop the box
258+
fn into_raw(mut self) -> *mut (dyn Future<Output = T> + 'a) {
259+
let ptr = unsafe { self.as_mut().get_unchecked_mut() as *mut _ };
260+
mem::forget(self);
261+
ptr
262+
}
263+
264+
unsafe fn drop(ptr: *mut (dyn Future<Output = T> + 'a)) {
265+
drop(Pin::from(Box::from_raw(ptr)))
266+
}
267+
}
268+
269+
unsafe impl<'a, T: 'a> UnsafeFutureObj<'a, T> for Pin<Box<dyn Future<Output = T> + 'a>> {
270+
fn into_raw(mut self) -> *mut (dyn Future<Output = T> + 'a) {
271+
let ptr = unsafe { self.as_mut().get_unchecked_mut() as *mut _ };
272+
mem::forget(self);
273+
ptr
274+
}
275+
276+
unsafe fn drop(ptr: *mut (dyn Future<Output = T> + 'a)) {
277+
drop(Pin::from(Box::from_raw(ptr)))
278+
}
279+
}
280+
281+
unsafe impl<'a, T: 'a> UnsafeFutureObj<'a, T> for Pin<Box<dyn Future<Output = T> + Send + 'a>> {
282+
fn into_raw(mut self) -> *mut (dyn Future<Output = T> + 'a) {
283+
let ptr = unsafe { self.as_mut().get_unchecked_mut() as *mut _ };
284+
mem::forget(self);
219285
ptr
220286
}
221287

222-
unsafe fn poll(ptr: *mut (), cx: &mut Context<'_>) -> Poll<T> {
223-
let ptr = ptr as *mut F;
224-
let pin: Pin<&mut F> = Pin::new_unchecked(&mut *ptr);
225-
F::poll(pin, cx)
288+
unsafe fn drop(ptr: *mut (dyn Future<Output = T> + 'a)) {
289+
drop(Pin::from(Box::from_raw(ptr)))
290+
}
291+
}
292+
293+
impl<'a, F: Future<Output = ()> + Send + 'a> From<Box<F>> for FutureObj<'a, ()> {
294+
fn from(boxed: Box<F>) -> Self {
295+
FutureObj::new(boxed)
226296
}
297+
}
227298

228-
unsafe fn drop(ptr: *mut ()) {
229-
#[allow(clippy::cast_ptr_alignment)]
230-
drop(Pin::from(Box::from_raw(ptr as *mut F)));
299+
impl<'a> From<Box<dyn Future<Output = ()> + Send + 'a>> for FutureObj<'a, ()> {
300+
fn from(boxed: Box<dyn Future<Output = ()> + Send + 'a>) -> Self {
301+
FutureObj::new(boxed)
231302
}
232303
}
233304

@@ -237,20 +308,32 @@ mod if_alloc {
237308
}
238309
}
239310

240-
impl<'a, F: Future<Output = ()> + Send + 'a> From<Box<F>> for FutureObj<'a, ()> {
241-
fn from(boxed: Box<F>) -> Self {
311+
impl<'a> From<Pin<Box<dyn Future<Output = ()> + Send + 'a>>> for FutureObj<'a, ()> {
312+
fn from(boxed: Pin<Box<dyn Future<Output = ()> + Send + 'a>>) -> Self {
242313
FutureObj::new(boxed)
243314
}
244315
}
245316

317+
impl<'a, F: Future<Output = ()> + 'a> From<Box<F>> for LocalFutureObj<'a, ()> {
318+
fn from(boxed: Box<F>) -> Self {
319+
LocalFutureObj::new(boxed)
320+
}
321+
}
322+
323+
impl<'a> From<Box<dyn Future<Output = ()> + 'a>> for LocalFutureObj<'a, ()> {
324+
fn from(boxed: Box<dyn Future<Output = ()> + 'a>) -> Self {
325+
LocalFutureObj::new(boxed)
326+
}
327+
}
328+
246329
impl<'a, F: Future<Output = ()> + 'a> From<Pin<Box<F>>> for LocalFutureObj<'a, ()> {
247330
fn from(boxed: Pin<Box<F>>) -> Self {
248331
LocalFutureObj::new(boxed)
249332
}
250333
}
251334

252-
impl<'a, F: Future<Output = ()> + 'a> From<Box<F>> for LocalFutureObj<'a, ()> {
253-
fn from(boxed: Box<F>) -> Self {
335+
impl<'a> From<Pin<Box<dyn Future<Output = ()> + 'a>>> for LocalFutureObj<'a, ()> {
336+
fn from(boxed: Pin<Box<dyn Future<Output = ()> + 'a>>) -> Self {
254337
LocalFutureObj::new(boxed)
255338
}
256339
}

futures-util/src/future/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -493,8 +493,8 @@ pub trait FutureExt: Future {
493493

494494
/// Wrap the future in a Box, pinning it.
495495
#[cfg(feature = "alloc")]
496-
fn boxed(self) -> BoxFuture<'static, Self::Output>
497-
where Self: Sized + Send + 'static
496+
fn boxed<'a>(self) -> BoxFuture<'a, Self::Output>
497+
where Self: Sized + Send + 'a
498498
{
499499
Box::pin(self)
500500
}

futures/tests/future_obj.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#![feature(async_await)]
22

3-
use futures::future::{Future, FutureObj};
3+
use futures::future::{Future, FutureObj, FutureExt};
44
use std::pin::Pin;
55
use futures::task::{Context, Poll};
66

77
#[test]
88
fn dropping_does_not_segfault() {
9-
FutureObj::new(Box::new(async { String::new() }));
9+
FutureObj::new(async { String::new() }.boxed());
1010
}
1111

1212
#[test]
@@ -29,7 +29,7 @@ fn dropping_drops_the_future() {
2929
}
3030
}
3131

32-
FutureObj::new(Box::new(Inc(&mut times_dropped)));
32+
FutureObj::new(Inc(&mut times_dropped).boxed());
3333

3434
assert_eq!(times_dropped, 1);
3535
}

0 commit comments

Comments
 (0)