Actix-web: Undefined behavior due to unsafe pinning of BodyStream

Created on 24 Jan 2020  路  6Comments  路  Source: actix/actix-web

Expected Behavior

The program below should not segfault when I only write 'safe' code.

Current Behavior

The program below segfaults.

Possible Solution

Change the MessageBody trait to take a Pin<&mut self> instead of a &mut self.

Steps to Reproduce (for bugs)

Run the following code in debug mode.

use futures::task::{noop_waker, Context};
use futures::stream::once;
use actix_http::body::{MessageBody, BodyStream};
use bytes::Bytes;

fn main() {
    let (sender, receiver) = futures::channel::oneshot::channel();
    let mut body_stream = Ok(BodyStream::new(once(async {
        let x = Box::new(0);
        let y = &x;
        receiver.await.unwrap();
        let z = **y;
        Ok::<_, ()>(Bytes::new())
    })));

    let waker = noop_waker();
    let mut context = Context::from_waker(&waker);

    let _ = body_stream.as_mut().unwrap().poll_next(&mut context);
    sender.send(()).unwrap();
    let _ = std::mem::replace(&mut body_stream, Err([0; 32])).unwrap().poll_next(&mut context);
}

Context

I found this problem by searching for 'unsafe' in the actix-web repo.

  • Rust Version (I.e, output of rustc -V): rustc 1.41.0-nightly
  • Actix Web Version: actix-http v1.0.1
C-bug UB unsafe

Most helpful comment

I dunno atm. But it feels that we will have to refactor all the poll-like methods to accept Pin<&mut Self> eventually, one way or another. It's to hard to control and keep in mind all the &mut self<->Pin<&mut Self> bridges with their invariants/tradeoffs. Even more, future contributions will definitely break the invariants, accidentally and quite often. Here the type system should do its job.

All 6 comments

Confirmed the test is crashing test runner.

Provided possible fix will be massive and break actix-web back compatibility as MessageBody trait is used in actix-http, awc and actix-web crates. Is there any other solution?

I dunno atm. But it feels that we will have to refactor all the poll-like methods to accept Pin<&mut Self> eventually, one way or another. It's to hard to control and keep in mind all the &mut self<->Pin<&mut Self> bridges with their invariants/tradeoffs. Even more, future contributions will definitely break the invariants, accidentally and quite often. Here the type system should do its job.

I found a similar issue in actix-codec, if you are going to make a breaking change here then you will probably need one there as well.

https://github.com/actix/actix-net/issues/91

Would this be a 2.x release though if we decide to do this?

Should we refactor and shoot for a 3.0 transition for this? I think 2+ has been a good halfway point but I really want to make async/await first order if possible soon.

IMO we _should_ refactor these unsafe's and shoot for a 3.0 release with a reasonably long alpha/beta period.

I think that's the best path forward as well now that Future is stable but it'll be hard to "backport" any new work. We most likely wouldn't be able to work on 2+ changes and 3.0 release simultaneously.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

djc picture djc  路  3Comments

alex picture alex  路  4Comments

zhaobingss picture zhaobingss  路  4Comments

naturallymitchell picture naturallymitchell  路  4Comments

sebzim4500 picture sebzim4500  路  3Comments