diff --git a/crates/linux/process-backend/src/lib.rs b/crates/linux/process-backend/src/lib.rs index af5aeea6..153e9380 100644 --- a/crates/linux/process-backend/src/lib.rs +++ b/crates/linux/process-backend/src/lib.rs @@ -101,4 +101,6 @@ pub enum Error { Transport(#[source] remote::transport::BackendError), #[error("buffer was too small to contain the result")] BufferTooSmall, + #[error("the remote executor is unusable after a previous error")] + TransportPoisoned, } diff --git a/crates/linux/process-backend/src/remote/backend.rs b/crates/linux/process-backend/src/remote/backend.rs index f42e36c6..b153dc5b 100644 --- a/crates/linux/process-backend/src/remote/backend.rs +++ b/crates/linux/process-backend/src/remote/backend.rs @@ -20,10 +20,10 @@ enum TransportState { } impl TransportState { - fn expect_ready(&mut self) -> &mut T { + fn ready(&mut self) -> Result<&mut T> { match self { - TransportState::Ready(transport) => transport, - TransportState::Poisoned => panic!("attempted to use poisoned transport"), + TransportState::Ready(transport) => Ok(transport), + TransportState::Poisoned => Err(Error::TransportPoisoned), } } } @@ -60,7 +60,7 @@ impl Backend { F: for<'output> FnOnce(Op::Output<'output>) -> Result, { let mut transport_state = self.transport_state.borrow_mut(); - let transport = transport_state.expect_ready(); + let transport = transport_state.ready()?; let e = match Op::request(transport, args) { Ok(response) => { diff --git a/crates/linux/process-backend/tests/basic.rs b/crates/linux/process-backend/tests/basic.rs index b135d984..2bcd12f6 100644 --- a/crates/linux/process-backend/tests/basic.rs +++ b/crates/linux/process-backend/tests/basic.rs @@ -97,3 +97,22 @@ fn basic() { executor_thread.join().unwrap().unwrap(); } + +#[test] +fn poisoned_transport_returns_error() { + let (backend_io, executor_io) = UnixStream::pair().unwrap(); + // Forcefully break the connection + drop(executor_io); + + let output_buf = vec![0u8; MAX_OUTPUT_LEN]; + let backend = Backend::new(transport::postcard::Backend::new(backend_io, output_buf)); + + assert!(matches!( + backend.stat_file(c"/"), + Err(process_backend::Error::Transport(_)) + )); + assert!(matches!( + backend.stat_file(c"/"), + Err(process_backend::Error::TransportPoisoned) + )); +}