Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Simon Marchi <simon.marchi@efficios.com>
To: gdb-patches@sourceware.org
Cc: Simon Marchi <simon.marchi@polymtl.ca>
Subject: [PATCH 1/2] gdb: don't let SIGPIPE kill GDB in the pipe command
Date: Tue, 13 Oct 2026 13:13:30 -0400	[thread overview]
Message-ID: <20261013171340.1748775-1-simon.marchi@efficios.com> (raw)

From: Simon Marchi <simon.marchi@polymtl.ca>

Aditya Kamath reported [1] that gdb.base/shell.exp sometimes fails on
AIX, because GDB gets killed by SIGPIPE when running:

    |p 123| exit 0

pipe_command opens the shell command with popen and writes the output
of the GDB command to it.  If the shell command exits without reading
its input, as is the case here, writing to the pipe raises SIGPIPE,
whose default action is to terminate the process.  It is a race: if the
shell command exits before GDB flushes its output, GDB dies.

On Linux, this is usually hidden by the fact that, when initialized by
GDB, Python sets SIGPIPE to be ignored.  This happens with all of GDB's
Python initialization paths:

 - Python < 3.9: GDB calls Py_Initialize, which calls
   Py_InitializeEx(1), meaning install_signal_handlers is enabled.

 - Python 3.9 to 3.13: GDB initializes a PyConfig with
   PyConfig_InitPythonConfig, which sets install_signal_handlers to 1 by
   default, and passes it to Py_InitializeFromConfig.

 - Python >= 3.14: GDB uses the PyInitConfig API, which starts from an
   isolated configuration (install_signal_handlers set to 0), but
   explicitly sets the install_signal_handlers option to true.

Fix it by ignoring SIGPIPE for the duration of pipe_command, using
scoped_ignore_sigpipe.  Writes to the pipe then fail with EPIPE, which
stdio_file ignores.

Add a test that pipes a large amount of output to shell commands that
don't read all their 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.

When Python is available, the test restores the default SIGPIPE action,
to test the behavior of a GDB built without Python.  Without the fix,
GDB gets killed by SIGPIPE.

[1] https://inbox.sourceware.org/gdb-patches/DSWPR15MB319817D17B50D16301CEEACAEED69E2@DSWPR15MB319817.namprd15.prod.outlook.com/

Change-Id: Id1ec076550ab94e6efb53d31bfca8e50a7c7c73d
---
 gdb/cli/cli-cmds.c               | 13 ++++++++++++
 gdb/testsuite/gdb.base/shell.exp | 34 ++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 8a85c8132776..bb7a7acbc3ac 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -59,6 +59,7 @@
 #include "gdbsupport/pathstuff.h"
 #include "gdbsupport/gdb_tilde_expand.h"
 #include "gdbsupport/eintr.h"
+#include "gdbsupport/scoped_ignore_signal.h"
 
 #ifdef TUI
 #include "tui/tui.h"
@@ -1158,6 +1159,18 @@ pipe_command (const char *arg, int from_tty)
 
   int exit_status;
   {
+    /* If GDB writes to the pipe after the sub-process has exited (for example,
+       with "lots-of-output | head -1"), GDB would receive a SIGPIPE, whose
+       default behavior is to end the process.  Ignore SIGPIPE for the duration
+       of the command.
+
+       With SIGPIPE ignored, the writes will fail with EPIPE, which stdio_file
+       ignores.
+
+       Note that if GDB is built with Python, SIGPIPE will already be ignored,
+       since that is done during Python initialization.  */
+    scoped_ignore_sigpipe ignore_sigpipe;
+
     SCOPE_EXIT { 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 f6b36dc3a7ca..272ce070ce1a 100644
--- a/gdb/testsuite/gdb.base/shell.exp
+++ b/gdb/testsuite/gdb.base/shell.exp
@@ -195,3 +195,37 @@ foreach cmd {"pipe " "| " "|"} {
     test_gdb_complete_none \
 	"${cmd}-d set maint set "
 }
+
+# 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.
+
+proc_with_prefix test_pipe_reader_exits_early {} {
+    clean_restart
+
+    # When Python is initialized, it sets SIGPIPE to be ignored.  Restore
+    # the default action, to test the behavior of a GDB built without
+    # Python.
+    if { [allow_python_tests] } {
+	gdb_test_no_output \
+	    "python import signal; signal.signal(signal.SIGPIPE, signal.SIG_DFL)" \
+	    "restore default SIGPIPE action"
+    }
+
+    # Define the "lots" command, which outputs 1000 lines of 200
+    # characters.
+    set line [string repeat "this is a line of output " 8]
+    gdb_define_cmd "lots" [list \
+			       {set $i = 0} \
+			       {while $i < 1000} \
+			       "echo $line\\n" \
+			       {set $i = $i + 1} \
+			       {end}]
+
+    gdb_test "pipe lots | exit 0"
+    gdb_test "pipe lots | exit 1"
+    gdb_test "pipe lots | head -1"
+}
+
+test_pipe_reader_exits_early

base-commit: bad8b979b27e050b2b4db16a261f8a78e24b8aa2
-- 
2.56.0


             reply	other threads:[~2026-10-13 17:13 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-13 17:13 Simon Marchi [this message]
2026-10-13 17:13 ` [PATCH 2/2] gdb: preserve shell command exit status in pipe command on EPIPE Simon Marchi
2026-10-14 12:46   ` 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-1-simon.marchi@efficios.com \
    --to=simon.marchi@efficios.com \
    --cc=gdb-patches@sourceware.org \
    --cc=simon.marchi@polymtl.ca \
    /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