Skip to content

.map_unchecked_mut() is unsound for self-referential types #9

@GoldsteinE

Description

@GoldsteinE

Hi! I’ve recently created a similar crate, but without dynamic dispatch and with automatic size calculation and Send/Sync inference, and found a problem with using .map_unchecked_mut() in .poll().

This line:

https://github.com/microsoft/stackfuture/blob/ae58939/src/lib.rs#L207

causes a retag of the whole byte array, invalidating all internal references inside of a future. To prevent this, you should directly transmute Pin<&mut MaybeUninit[u8; _]> instead of mapping.

This is a simple testcase that fails under Miri (adapted from futures-rs test suite):

use futures::{
    channel::mpsc,
    executor::block_on,
    sink::SinkExt as _,
    stream::{Stream, StreamExt as _},
};
use stackfuture::StackFuture;
use std::thread;

#[test]
fn stress_drop_sender() {
    const ITER: usize = if cfg!(miri) { 100 } else { 10000 };

    fn list() -> impl Stream<Item = i32> {
        let (tx, rx) = mpsc::channel(1);
        thread::spawn(move || {
            block_on(send_one_two_three(tx));
        });
        rx
    }

    for _ in 0..ITER {
        let v: Vec<_> = block_on(list().collect());
        assert_eq!(v, vec![1, 2, 3]);
    }
}

fn send_one_two_three(mut tx: mpsc::Sender<i32>) -> StackFuture<'static, (), 512> {
    StackFuture::from(async move {
        for i in 1..=3 {
            tx.send(i).await.unwrap();
        }
    })
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions