From: Tom de Vries Date: Tue, 29 Apr 2025 15:01:55 +0000 (+0200) Subject: [gdb] Fix sig_write for null gdb_stderr X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cb8c89ba54bc5b580e2af78cc28f33d21b540423;p=thirdparty%2Fbinutils-gdb.git [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) 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) 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: . Segmentation fault (core dumped) $ q ... Tested on x86_64-linux. Approved-By: Simon Marchi --- diff --git a/gdb/bt-utils.c b/gdb/bt-utils.c index 98726e78f54..922402eefc0 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 ad9459e3cbf..968117c171c 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