diff --git a/CHANGELOG.md b/CHANGELOG.md index 6544b5f..187c479 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Fixed clipboard crashing, when seat has neither keyboard nor pointer focus - Advertise UTF8_STRING mimetype +- Fixed crash when writing data to the server fails - Fixed fd leaking from keymap updates ## 0.5.1 -- 2020-07-10 diff --git a/src/lib.rs b/src/lib.rs index 26fc5ad..1d03b87 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,10 +43,17 @@ impl Clipboard { /// Loads content from a clipboard on a last observed seat. pub fn load(&self) -> Result { let _ = self.request_sender.send(worker::Command::Load); - self.request_receiver.recv().unwrap() + + if let Ok(reply) = self.request_receiver.recv() { + reply + } else { + // The clipboard thread is dead, however we shouldn't crash downstream, so + // propogating an error. + Err(std::io::Error::new(std::io::ErrorKind::Other, "clipboard is dead.")) + } } - /// Store to a clipboard + /// Store to a clipboard. /// /// Stores to a clipboard on a last observed seat. pub fn store>(&self, text: T) { @@ -59,7 +66,14 @@ impl Clipboard { /// Loads content from a primary clipboard on a last observed seat. pub fn load_primary(&self) -> Result { let _ = self.request_sender.send(worker::Command::LoadPrimary); - self.request_receiver.recv().unwrap() + + if let Ok(reply) = self.request_receiver.recv() { + reply + } else { + // The clipboard thread is dead, however we shouldn't crash downstream, so + // propogating an error. + Err(std::io::Error::new(std::io::ErrorKind::Other, "clipboard is dead.")) + } } /// Store to a primary clipboard. @@ -74,7 +88,7 @@ impl Clipboard { impl Drop for Clipboard { fn drop(&mut self) { // Shutdown smithay-clipboard. - self.request_sender.send(worker::Command::Exit).unwrap(); + let _ = self.request_sender.send(worker::Command::Exit); if let Some(clipboard_thread) = self.clipboard_thread.take() { let _ = clipboard_thread.join(); } diff --git a/src/worker/handlers.rs b/src/worker/handlers.rs index d372a91..08ca172 100644 --- a/src/worker/handlers.rs +++ b/src/worker/handlers.rs @@ -41,7 +41,12 @@ macro_rules! handle_load { } }; - $queue.sync_roundtrip(&mut (), |_, _, _| unreachable!()).unwrap(); + // If we fail here, it means that we likely won't be able + // to read clipboard anyway, so return and reply to prevent block/crash. + if $queue.sync_roundtrip(&mut (), |_, _, _| unreachable!()).is_err() { + handlers::reply_error(&$tx, "failed to access clipboard."); + return; + }; let mut contents = String::new(); let result = reader.read_to_string(&mut contents).map(|_| { @@ -52,7 +57,7 @@ macro_rules! handle_load { } }); - $tx.send(result).unwrap(); + let _ = $tx.send(result); }); // Send back that we've failed to load data from the clipboard. @@ -86,7 +91,7 @@ macro_rules! handle_store { /// Reply an error to a clipboard master. pub fn reply_error(tx: &Sender>, description: &str) { - tx.send(Err(std::io::Error::new(std::io::ErrorKind::Other, description))).unwrap(); + let _ = tx.send(Err(std::io::Error::new(std::io::ErrorKind::Other, description))); } /// Update seat and serial on pointer events. diff --git a/src/worker/mod.rs b/src/worker/mod.rs index cf54b1a..75304fb 100644 --- a/src/worker/mod.rs +++ b/src/worker/mod.rs @@ -68,7 +68,12 @@ fn worker_impl(display: Display, request_rx: Receiver, reply_tx: Sender let env = Environment::init(&display_proxy, SmithayClipboard::new()); let req = queue.sync_roundtrip(&mut (), |_, _, _| unreachable!()); - let _ = req.and_then(|_| queue.sync_roundtrip(&mut (), |_, _, _| unreachable!())).unwrap(); + let req = req.and_then(|_| queue.sync_roundtrip(&mut (), |_, _, _| unreachable!())); + + // We shouldn't crash the application if we've failed to dispatch. + if req.is_err() { + return; + } // Get data device manager. let data_device_manager = env.get_global::(); @@ -209,7 +214,12 @@ fn worker_impl(display: Display, request_rx: Receiver, reply_tx: Sender // Reset the time we're sleeping. sa_tracker.reset_sleep(); - queue.sync_roundtrip(&mut dispatch_data, |_, _, _| unimplemented!()).unwrap(); + if queue.sync_roundtrip(&mut dispatch_data, |_, _, _| unimplemented!()).is_err() { + if request == Command::LoadPrimary || request == Command::Load { + handlers::reply_error(&reply_tx, "primary clipboard is not available."); + break; + } + } // Get latest observed seat and serial. let (seat, serial) = match dispatch_data.last_seat() { @@ -270,7 +280,10 @@ fn worker_impl(display: Display, request_rx: Receiver, reply_tx: Sender } } - let pending_events = queue.dispatch_pending(&mut dispatch_data, |_, _, _| {}).unwrap(); + let pending_events = match queue.dispatch_pending(&mut dispatch_data, |_, _, _| {}) { + Ok(pending_events) => pending_events, + Err(_) => break, + }; // If some application is trying to spam us when there're no seats, it's likely that // someone is trying to paste from us.