From 9c07eca83544259fdb01bc1f553cbb99b00fef5c Mon Sep 17 00:00:00 2001 From: Simon Chopin Date: Tue, 20 Oct 2026 15:17:31 +0200 Subject: [PATCH] process-backend: don't panic on transport failure Panics should be avoided, as crashing the crash helper is not particularly helpful (or even actively harmful on Android). This will likely result in crash reports with a few similar looking poison errors in their SoftError streams as various systems attempt to get their data, but that's preferrable to no report at all. --- crates/linux/process-backend/src/lib.rs | 2 ++ .../process-backend/src/remote/backend.rs | 8 ++++---- crates/linux/process-backend/tests/basic.rs | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 4 deletions(-) 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) + )); +}