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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions