From: Simon Marchi <simon.marchi@efficios.com>
To: gdb-patches@sourceware.org
Cc: Simon Marchi <simon.marchi@efficios.com>
Subject: [PATCH 2/2] gdb: preserve shell command exit status in pipe command on EPIPE
Date: Tue, 13 Oct 2026 13:13:31 -0400 [thread overview]
Message-ID: <20261013171340.1748775-2-simon.marchi@efficios.com> (raw)
In-Reply-To: <20261013171340.1748775-1-simon.marchi@efficios.com>
When the shell command of the pipe command exits without reading all of
its input, the pipe command may fail with:
(gdb) pipe COMMAND | head -1
...
shell command "head -1" failed: Broken pipe
pclose flushes the buffered output before closing the stream. If that
flush fails, pclose may return -1 (with errno == EPIPE) instead of the
exit status of the shell command.
Work around this by flusing the stream explicitly before calling pclose,
ignoring errors. With that out of the way, pclose returns the exit
status of the shell command. This makes something like "pipe COMMAND |
head -1" behave like it would in a shell.
Update the test added in the previous commit to check the exit status
of the shell commands.
Change-Id: I939e4610f6c09ac2007a0c58f64480106c74edb2
---
gdb/cli/cli-cmds.c | 9 ++++++++-
gdb/testsuite/gdb.base/shell.exp | 17 +++++++++++++----
2 files changed, 21 insertions(+), 5 deletions(-)
diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index bb7a7acbc3ac..7aca84ff09ac 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -1171,7 +1171,14 @@ pipe_command (const char *arg, int from_tty)
since that is done during Python initialization. */
scoped_ignore_sigpipe ignore_sigpipe;
- SCOPE_EXIT { exit_status = pclose (to_shell_command); };
+ SCOPE_EXIT
+ {
+ /* Flush explicitly, ignoring errors, so that a failure to write
+ buffered output (for instance, with EPIPE) doesn't make pclose fail
+ and hide the exit status of the shell command. */
+ fflush (to_shell_command);
+ exit_status = pclose (to_shell_command);
+ };
stdio_file pipe_file (to_shell_command);
diff --git a/gdb/testsuite/gdb.base/shell.exp b/gdb/testsuite/gdb.base/shell.exp
index 272ce070ce1a..2e6c63585eb0 100644
--- a/gdb/testsuite/gdb.base/shell.exp
+++ b/gdb/testsuite/gdb.base/shell.exp
@@ -199,7 +199,8 @@ foreach cmd {"pipe " "| " "|"} {
# Test piping a lot of output to a shell command that exits without
# reading its input. The output is larger than the pipe buffer, so GDB
# necessarily writes to the pipe after the shell command has exited,
-# regardless of timing. GDB must not get killed by SIGPIPE.
+# regardless of timing. GDB must not get killed by SIGPIPE, and must
+# report the exit status of the shell command.
proc_with_prefix test_pipe_reader_exits_early {} {
clean_restart
@@ -223,9 +224,17 @@ proc_with_prefix test_pipe_reader_exits_early {} {
{set $i = $i + 1} \
{end}]
- gdb_test "pipe lots | exit 0"
- gdb_test "pipe lots | exit 1"
- gdb_test "pipe lots | head -1"
+ gdb_test_no_output "pipe lots | exit 0"
+ gdb_test "p \$_shell_exitcode" " = 0" "exit 0 exitcode"
+ gdb_test "p \$_shell_exitsignal" " = void" "exit 0 exitsignal"
+
+ gdb_test_no_output "pipe lots | exit 1"
+ gdb_test "p \$_shell_exitcode" " = 1" "exit 1 exitcode"
+ gdb_test "p \$_shell_exitsignal" " = void" "exit 1 exitsignal"
+
+ gdb_test "pipe lots | head -1" "^$line"
+ gdb_test "p \$_shell_exitcode" " = 0" "head -1 exitcode"
+ gdb_test "p \$_shell_exitsignal" " = void" "head -1 exitsignal"
}
test_pipe_reader_exits_early
--
2.56.0
next prev parent reply other threads:[~2026-10-13 17:14 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-13 17:13 [PATCH 1/2] gdb: don't let SIGPIPE kill GDB in the pipe command Simon Marchi
2026-10-13 17:13 ` Simon Marchi [this message]
2026-10-14 12:46 ` [PATCH 2/2] gdb: preserve shell command exit status in pipe command on EPIPE Tom Tromey
2026-10-14 9:32 ` [PATCH 1/2] gdb: don't let SIGPIPE kill GDB in the pipe command Aditya Kamath
2026-10-14 12:42 ` Tom Tromey
2026-10-14 12:56 ` Simon Marchi
2026-10-14 12:46 ` Tom Tromey
2026-10-14 12:57 ` Simon Marchi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261013171340.1748775-2-simon.marchi@efficios.com \
--to=simon.marchi@efficios.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox