+
Skip to content

cat: handle broken pipe gracefully #8336

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft

cat: handle broken pipe gracefully #8336

wants to merge 1 commit into from

Conversation

tgrez
Copy link
Contributor

@tgrez tgrez commented Jul 12, 2025

Fixes #6876.

I was able to reproduce the original issue with both:

$ echo a | gzip -c > f.gz
$ perl -e '
      use POSIX qw(dup2);
      $SIG{PIPE} = "DEFAULT";
      pipe my ($read_end, $write_end);
      dup2 fileno $write_end, 1;
      close $read_end;
      exec "cat", "f.gz", "f.gz";
  '

cat: f.gz: EPIPE: Broken pipe
cat: f.gz: EPIPE: Broken pipe

and:

$ cat f.gz | false
cat: f.gz: EPIPE: Broken pipe

This PR fixes both cases.

Preparing yet another similar fix (previous ones: #8327 and #8312) I wonder if it makes sense to fix it for all binaries in a single place (at least for non-windows platforms), like in uucore::main macro in src/uucore_procs/src/lib.rs:

             // disable rust signal handlers (otherwise processes don't dump core after e.g. one SIGSEGV)
             #[cfg(unix)]
             uucore::disable_rust_signal_handlers().expect("Disabling rust signal handlers failed");
+            // When we receive a SIGPIPE signal, we want to terminate the process so
+            // that we don't print any error messages to stderr. Rust ignores SIGPIPE
+            // (see https://github.com/rust-lang/rust/issues/62569), so we restore it's
+            // default action here.
+            #[cfg(not(target_os = "windows"))]
+            unsafe {
+                libc::signal(libc::SIGPIPE, libc::SIG_DFL);
+            }
             let result = uumain(args);
             match result {
                 Ok(()) => uucore::error::get_exit_code(),

I can update this PR if such general fix makes sense.

@tgrez
Copy link
Contributor Author

tgrez commented Jul 12, 2025

Also, assuming those fish shell tests are located here: https://github.com/fish-shell/fish-shell/blob/e9bb150a41b64bc0d4cd3784d6fd54e0eabb4b42/tests/checks/pipestatus.fish#L200

This bug:

$ cat /dev/zero | dd > /not/a/valid/path
bash: /not/a/valid/path: No such file or directory
cat: /dev/zero: EPIPE: Broken pipe

is also fixed (verified in bash shell, but the error message is no longer present):

$ cat /dev/zero | dd > /not/a/valid/path
bash: /not/a/valid/path: No such file or directory
$

@tgrez tgrez marked this pull request as draft July 12, 2025 14:15
@tgrez
Copy link
Contributor Author

tgrez commented Jul 12, 2025

Setting to draft until CI errors are resolved.

Copy link

GNU testsuite comparison:

Skipping an intermittent issue tests/misc/stdbuf (passes in this run but fails in the 'main' branch)
Skipping an intermittent issue tests/misc/tee (passes in this run but fails in the 'main' branch)
Skipping an intermittent issue tests/timeout/timeout (passes in this run but fails in the 'main' branch)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

cat: /dev/zero: EPIPE: Broken pipe when running fish shell tests
1 participant
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载