Closed
Description
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
Labels
No labels