Skip to content

BiLock assertion failure and segfault in --release mode (single-threaded!) #296

Closed
@dwrensha

Description

@dwrensha

Consider the following program (which has been minimized from a much more complex situation):

# Cargo.toml
[package]
name = "crash"
version = "0.0.1"

[[bin]]
name = "crash"
path = "crash.rs"

[dependencies]
futures = "=0.1.6"
tokio-core = "=0.1.1"
mio-uds = "=0.6.0"
// crash.rs
extern crate futures;
extern crate tokio_core;
extern crate mio_uds;

use futures::{Async, Future, Poll};
use futures::sync::oneshot;
use tokio_core::io::Io;

enum State<W> {
    Writing(W, oneshot::Sender<()>),
    BetweenWrites(W),
    Empty,
}

pub struct WriteQueue<W>  {
    pending: Option<oneshot::Sender<()>>,
    state: State<W>,
}

impl <W> WriteQueue<W> {
    pub fn new(writer: W) -> WriteQueue<W>
    {
        let (complete, _) = futures::oneshot();
        WriteQueue {
            pending: Some(complete),
            state: State::BetweenWrites(writer),
        }
    }
}

enum IntermediateState<W> {
    WriteDone(W),
    StartWrite(oneshot::Sender<()>),
    Resolve,
}

impl <W> Future for WriteQueue<W> {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            let next: IntermediateState<W> = match self.state {
                State::Writing(_, _) => return Err(()),
                State::BetweenWrites(ref mut _writer) => {
                    let front = self.pending.take();
                    match front {
                        Some(complete) => {
                            IntermediateState::StartWrite(complete)
                        }
                        None => {
                            IntermediateState::Resolve
                        }
                    }
                }
                State::Empty => unimplemented!(),
            };

            match next {
                IntermediateState::WriteDone(_w) => unimplemented!(),
                IntermediateState::StartWrite(c) => {
                    let new_state = match ::std::mem::replace(&mut self.state, State::Empty) {
                        State::BetweenWrites(w) => {
                            State::Writing(w, c)
                        }
                        _ => unreachable!(),
                    };
                    self.state = new_state;
                }
                IntermediateState::Resolve => {
                    match ::std::mem::replace(&mut self.state, State::Empty) {
                        State::BetweenWrites(_w) => {
                            return Ok(Async::Ready(()))
                        }
                        _ => unreachable!(),
                    }
                }
            }
        }
    }
}

pub fn main() {
    let mut core = ::tokio_core::reactor::Core::new().unwrap();
    let (_, server_stream) = ::mio_uds::UnixStream::pair().unwrap();
    let handle = core.handle();
    let (_, server_writer) = ::tokio_core::reactor::PollEvented::new(server_stream, &handle).unwrap().split();
    let _ = core.run(WriteQueue::new(server_writer));
}

If I run it in debug mode, it exits without error, as I would expect. If I run in in release mode, I see, to my surprise:

$ RUST_BACKTRACE=1 ./target/release/crash 
thread 'main' panicked at 'assertion failed: `(left == right)` (left: `1`, right: `0`)', /Users/dwrensha/.multirust/toolchains/stable/cargo/registry/src/github.com-1ecc6299db9ec823/futures-0.1.6/src/lib.rs:195
stack backtrace:
   1:        0x100960408 - std::sys::backtrace::tracing::imp::write::h6f1d53a70916b90d
   2:        0x10096256f - std::panicking::default_hook::{{closure}}::h137e876f7d3b5850
   3:        0x1009616c5 - std::panicking::default_hook::h0ac3811ec7cee78c
   4:        0x100961c16 - std::panicking::rust_panic_with_hook::hc303199e04562edf
   5:        0x100961ab4 - std::panicking::begin_panic::h6ed03353807cf54d
   6:        0x1009619d2 - std::panicking::begin_panic_fmt::hc321cece241bb2f5
   7:        0x10095261f - <alloc::arc::Arc<T>>::drop_slow::h94a0b56e89cad006
   8:        0x100953dfb - crash::main::hddfbd08facd330e5
   9:        0x100962b2a - __rust_maybe_catch_panic
  10:        0x100961206 - std::rt::lang_start::h538f8960e7644c80
Segmentation fault: 11

The assertion being tripped is in BiLock::drop()

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