aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom de Vries <tdevries@suse.de>2025-04-29 17:01:55 +0200
committerTom de Vries <tdevries@suse.de>2025-04-29 17:01:55 +0200
commitcb8c89ba54bc5b580e2af78cc28f33d21b540423 (patch)
tree625f9e0bb22b9d2584ce27dd1c6761d035237676
parent27ff35ce34d89687feb2584d0eb9102218ee9e74 (diff)
downloadbinutils-cb8c89ba54bc5b580e2af78cc28f33d21b540423.zip
binutils-cb8c89ba54bc5b580e2af78cc28f33d21b540423.tar.gz
binutils-cb8c89ba54bc5b580e2af78cc28f33d21b540423.tar.bz2
[gdb] Fix sig_write for null gdb_stderr
When running test-case gdb.tui/tui-layout-asm.exp with target board dwarf5-fission-debug-types, the test-case fails and I get a core dump: ... # of unexpected core files 1 ... Looking at the backtrace of the core file, what seems to be happening is that: - gdbpy_flush attempts to flush gdb_stdout, which is nullptr - that causes a segfault - gdb intercepts this and starts to handle it using handle_fatal_signal - handle_fatal_signal calls sig_write, which attempts to write to gdb_stderr, which is nullptr, - that causes another segfault - gdb exits I managed to reproduce the problem by the following trigger patch in stdin_event_handler: ... - if (error) + if (1 || error) { current_ui = main_ui; ui->unregister_file_handler (); - if (main_ui == ui) + if (1 || main_ui == ui) { gdb_printf (gdb_stderr, _("error detected on stdin\n")); + gdb_stderr = nullptr; + gdb_stdout = nullptr; + gdb_stdlog = nullptr; quit_command ((char *) 0, 0); } ... which gives us: ... $ gdb (gdb) <q>error detected on stdin Segmentation fault (core dumped) $ q ... Fix sig_write to handle the case that gdb_stderr == nullptr, such that we get instead: ... $ gdb (gdb) <q>error detected on stdin Fatal signal: Segmentation fault ----- Backtrace ----- ... --------------------- A fatal error internal to GDB has been detected, further debugging is not possible. GDB will now terminate. This is a bug, please report it. For instructions, see: <https://www.gnu.org/software/gdb/bugs/>. Segmentation fault (core dumped) $ q ... Tested on x86_64-linux. Approved-By: Simon Marchi <simon.marchi@efficios.com>
-rw-r--r--gdb/bt-utils.c15
-rw-r--r--gdb/event-top.c8
2 files changed, 16 insertions, 7 deletions
diff --git a/gdb/bt-utils.c b/gdb/bt-utils.c
index 98726e7..922402e 100644
--- a/gdb/bt-utils.c
+++ b/gdb/bt-utils.c
@@ -45,7 +45,10 @@ gdb_internal_backtrace_set_cmd (const char *args, int from_tty,
void
sig_write (const char *msg)
{
- gdb_stderr->write_async_safe (msg, strlen (msg));
+ if (gdb_stderr == nullptr || gdb_stderr->fd () == -1)
+ std::ignore = ::write (2, msg, strlen (msg));
+ else
+ gdb_stderr->write_async_safe (msg, strlen (msg));
}
#ifdef GDB_PRINT_INTERNAL_BACKTRACE
@@ -130,7 +133,10 @@ gdb_internal_backtrace_1 ()
void *buffer[25];
int frames = backtrace (buffer, ARRAY_SIZE (buffer));
- backtrace_symbols_fd (buffer, frames, gdb_stderr->fd ());
+ int fd = ((gdb_stderr == nullptr || gdb_stderr->fd () == -1)
+ ? 2
+ : gdb_stderr->fd ());
+ backtrace_symbols_fd (buffer, frames, fd);
if (frames == ARRAY_SIZE (buffer))
sig_write (_("Backtrace might be incomplete.\n"));
}
@@ -166,10 +172,7 @@ gdb_internal_backtrace ()
#ifdef GDB_PRINT_INTERNAL_BACKTRACE
sig_write (str_backtrace);
- if (gdb_stderr->fd () > -1)
- gdb_internal_backtrace_1 ();
- else
- sig_write (str_backtrace_unavailable);
+ gdb_internal_backtrace_1 ();
sig_write ("---------------------\n");
#endif
diff --git a/gdb/event-top.c b/gdb/event-top.c
index ad9459e..968117c 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -1022,7 +1022,13 @@ handle_fatal_signal (int sig)
}
sig_write ("\n\n");
- gdb_stderr->flush ();
+ if (gdb_stderr == nullptr || gdb_stderr->fd () == -1)
+ {
+ /* Writing to file descriptor instead of stream, no flush
+ required. */
+ }
+ else
+ gdb_stderr->flush ();
}
#endif