From d32aec59063afd832fd1111646cd662c82eb8357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Braulio=20Valdivielso=20Mart=C3=ADnez?= Date: Mon, 20 Dec 2021 23:08:41 +0000 Subject: [PATCH] Don't panic if the other end of std{out,err} is closed (#4179) * fix #4161 println! and friends will panic on BrokenPipe. The solution is to use writeln! instead, and ignore the error (or do we want to do something else?) * test that nu doesn't panic in case of BrokenPipe error * fixup! test that nu doesn't panic in case of BrokenPipe error * make do_not_panic_if_broken_pipe only run on UNIX systems --- crates/nu-protocol/src/macros.rs | 16 +++++++++++++--- tests/shell/mod.rs | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/crates/nu-protocol/src/macros.rs b/crates/nu-protocol/src/macros.rs index 52f26328b4..ef9a496c5e 100644 --- a/crates/nu-protocol/src/macros.rs +++ b/crates/nu-protocol/src/macros.rs @@ -6,7 +6,7 @@ macro_rules! out { ($($tokens:tt)*) => { use std::io::Write; - print!($($tokens)*); + write!(std::io::stdout(), $($tokens)*).unwrap_or(()); let _ = std::io::stdout().flush(); } } @@ -17,7 +17,12 @@ macro_rules! out { /// and stray printlns left by accident #[macro_export] macro_rules! outln { - ($($tokens:tt)*) => { println!($($tokens)*) } + ($($tokens:tt)*) => { + { + use std::io::Write; + writeln!(std::io::stdout(), $($tokens)*).unwrap_or(()) + } + } } /// Outputs to standard error @@ -26,7 +31,12 @@ macro_rules! outln { /// and stray printlns left by accident #[macro_export] macro_rules! errln { - ($($tokens:tt)*) => { eprintln!($($tokens)*) } + ($($tokens:tt)*) => { + { + use std::io::Write; + writeln!(std::io::stderr(), $($tokens)*).unwrap_or(()) + } + } } #[macro_export] diff --git a/tests/shell/mod.rs b/tests/shell/mod.rs index 3439220610..07fd1d17b0 100644 --- a/tests/shell/mod.rs +++ b/tests/shell/mod.rs @@ -53,3 +53,20 @@ fn plugins_are_declared_with_wix() { assert_eq!(actual.out, "0"); } + +#[test] +#[cfg(not(windows))] +fn do_not_panic_if_broken_pipe() { + // `nu -h | false` + // used to panic with a BrokenPipe error + let child_output = std::process::Command::new("sh") + .arg("-c") + .arg(format!( + "{:?} -h | false", + nu_test_support::fs::executable_path() + )) + .output() + .expect("failed to execute process"); + + assert!(child_output.stderr.is_empty()); +}