]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Fix signal unsafe call inside a signal
authorBernd Edlinger <bernd.edlinger@hotmail.de>
Mon, 20 May 2024 05:12:30 +0000 (07:12 +0200)
committerBernd Edlinger <bernd.edlinger@hotmail.de>
Tue, 29 Oct 2024 15:02:49 +0000 (16:02 +0100)
It can easily happen that the signal handler function
`handle_fatal_signal` uses various signal unsafe functions.
The problematic functions are `_` and `strsignal` which
can be pre-computed after the `setlocale` call is done.

Unfortunately when compiled with --disable-libbacktrace a
different code path is used, that calls the glibc function
`backtrace` which calls `malloc` and `free` and is therefore
also signal unsafe, that is probably unfixable, so there
is no attempt to fix anything in this code path.

Approved-By: Andrew Burgess <aburgess@redhat.com>
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31713#c9

gdb/bt-utils.c
gdb/bt-utils.h
gdb/event-top.c
gdb/main.c

index f658ce0d4bcd6ba6fe3346d4749adb27312fcc81..64d7701d5ae58395aa4e74aefb05eb7e06e5d461 100644 (file)
@@ -145,10 +145,25 @@ gdb_internal_backtrace_1 ()
 #else
 #error "unexpected internal backtrace policy"
 #endif
+
+static const char *str_backtrace = "----- Backtrace -----\n";
+static const char *str_backtrace_unavailable = "Backtrace unavailable\n";
+
 #endif /* GDB_PRINT_INTERNAL_BACKTRACE */
 
 /* See bt-utils.h.  */
 
+void
+gdb_internal_backtrace_init_str ()
+{
+#ifdef GDB_PRINT_INTERNAL_BACKTRACE
+  str_backtrace = _("----- Backtrace -----\n");
+  str_backtrace_unavailable = _("Backtrace unavailable\n");
+#endif
+}
+
+/* See bt-utils.h.  */
+
 void
 gdb_internal_backtrace ()
 {
@@ -161,12 +176,12 @@ gdb_internal_backtrace ()
     gdb_stderr->write_async_safe (msg, strlen (msg));
   };
 
-  sig_write (_("----- Backtrace -----\n"));
+  sig_write (str_backtrace);
 
   if (gdb_stderr->fd () > -1)
     gdb_internal_backtrace_1 ();
   else
-    sig_write (_("Backtrace unavailable\n"));
+    sig_write (str_backtrace_unavailable);
 
   sig_write ("---------------------\n");
 #endif
index ec2d14a548421f73d9064d2e135bbf80db6cb39a..1288ec705ef89d8a4409cf4308af9b277ac93cd4 100644 (file)
@@ -71,4 +71,8 @@ extern void gdb_internal_backtrace ();
 extern void gdb_internal_backtrace_set_cmd (const char *args, int from_tty,
                                            cmd_list_element *c);
 
+/* Initialize language specific strings.  */
+
+extern void gdb_internal_backtrace_init_str ();
+
 #endif /* BT_UTILS_H */
index d3cf144958a8ca867dc5e22eb030800cf5443a2a..e7556f71453d995b599da86f1c384fe6f24ded82 100644 (file)
@@ -908,6 +908,51 @@ unblock_signal (int sig)
   return false;
 }
 
+/* Signal safe language specific strings.  */
+
+#ifdef GDB_PRINT_INTERNAL_BACKTRACE
+static const char *str_fatal_signal;
+static const char *str_sigsegv;
+#ifdef SIGFPE
+static const char *str_sigfpe;
+#endif
+#ifdef SIGBUS
+static const char *str_sigbus;
+#endif
+#ifdef SIGABRT
+static const char *str_sigabrt;
+#endif
+static const char *str_unknown_signal;
+static const char *str_fatal_error_detected_gdb_will_now_terminate;
+static const char *str_this_is_a_bug;
+static const char *str_for_instructions_see;
+
+/* Initialize language specific strings.  */
+
+static void
+init_str_handle_fatal_signal ()
+{
+  str_fatal_signal = _("Fatal signal: ");
+  str_sigsegv = strsignal (SIGSEGV);
+#ifdef SIGFPE
+  str_sigfpe = strsignal (SIGFPE);
+#endif
+#ifdef SIGBUS
+  str_sigbus = strsignal (SIGBUS);
+#endif
+#ifdef SIGABRT
+  str_sigabrt = strsignal (SIGABRT);
+#endif
+  str_unknown_signal = _("Unknown signal");
+  str_fatal_error_detected_gdb_will_now_terminate =
+       _("A fatal error internal to GDB has been detected, "
+         "further\ndebugging is not possible.  GDB will now "
+         "terminate.\n\n");
+  str_this_is_a_bug = _("This is a bug, please report it.");
+  str_for_instructions_see = _("  For instructions, see:\n");
+}
+#endif
+
 /* Called to handle fatal signals.  SIG is the signal number.  */
 
 [[noreturn]] static void
@@ -926,19 +971,40 @@ handle_fatal_signal (int sig)
   if (bt_on_fatal_signal)
     {
       sig_write ("\n\n");
-      sig_write (_("Fatal signal: "));
-      sig_write (strsignal (sig));
+      sig_write (str_fatal_signal);
+      switch (sig)
+       {
+       case SIGSEGV:
+         sig_write (str_sigsegv);
+         break;
+#ifdef SIGFPE
+       case SIGFPE:
+         sig_write (str_sigfpe);
+         break;
+#endif
+#ifdef SIGBUS
+       case SIGBUS:
+         sig_write (str_sigbus);
+         break;
+#endif
+#ifdef SIGABRT
+       case SIGABRT:
+         sig_write (str_sigabrt);
+         break;
+#endif
+       default:
+         sig_write (str_unknown_signal);
+         break;
+       }
       sig_write ("\n");
 
       gdb_internal_backtrace ();
 
-      sig_write (_("A fatal error internal to GDB has been detected, "
-                  "further\ndebugging is not possible.  GDB will now "
-                  "terminate.\n\n"));
-      sig_write (_("This is a bug, please report it."));
+      sig_write (str_fatal_error_detected_gdb_will_now_terminate);
+      sig_write (str_this_is_a_bug);
       if (REPORT_BUGS_TO[0] != '\0')
        {
-         sig_write (_("  For instructions, see:\n"));
+         sig_write (str_for_instructions_see);
          sig_write (REPORT_BUGS_TO);
          sig_write (".");
        }
@@ -1066,6 +1132,10 @@ gdb_init_signals (void)
     create_async_signal_handler (async_sigtstp_handler, NULL, "sigtstp");
 #endif
 
+#ifdef GDB_PRINT_INTERNAL_BACKTRACE
+  init_str_handle_fatal_signal ();
+#endif
+
 #ifdef SIGFPE
   signal (SIGFPE, handle_fatal_signal);
 #endif
index e4a40c51023cd6bae8c1e45594ee2b4a7d6c2279..4370e95ada44a5ee4d919267e4feecd27354fdb2 100644 (file)
@@ -58,6 +58,7 @@
 #include "observable.h"
 #include "serial.h"
 #include "cli-out.h"
+#include "bt-utils.h"
 
 /* The selected interpreter.  */
 std::string interpreter_p;
@@ -676,6 +677,7 @@ captured_main_1 (struct captured_main_args *context)
   /* Note: `error' cannot be called before this point, because the
      caller will crash when trying to print the exception.  */
   main_ui = new ui (stdin, stdout, stderr);
+  gdb_internal_backtrace_init_str ();
   current_ui = main_ui;
 
   gdb_stdtarg = gdb_stderr;