aboutsummaryrefslogtreecommitdiff
path: root/gdb/event-top.c
diff options
context:
space:
mode:
authorTom Tromey <tom@tromey.com>2019-03-04 15:12:04 -0700
committerTom Tromey <tom@tromey.com>2019-11-26 14:02:57 -0700
commit3b3978bca2a204a772563c8e121e4a02be72e802 (patch)
tree70076c2fc0433920de0b7a71ae12b34311a5fdfa /gdb/event-top.c
parent9411c49ecc09df989ecddb05e1756e0a9da0d1c8 (diff)
downloadgdb-3b3978bca2a204a772563c8e121e4a02be72e802.zip
gdb-3b3978bca2a204a772563c8e121e4a02be72e802.tar.gz
gdb-3b3978bca2a204a772563c8e121e4a02be72e802.tar.bz2
Introduce thread-safe way to handle SIGSEGV
The gdb demangler installs a SIGSEGV handler in order to protect gdb from demangler bugs. However, this is not thread-safe, as signal handlers are global to the process. This patch changes gdb to always install a global SIGSEGV handler, and then lets threads indicate their interest in handling the signal by setting a thread-local variable. This patch then arranges for the demangler code to use this; being sure to arrange for calls to warning and the like to be done on the main thread. One thing I wondered while writing this patch is if there are any systems that do not have "sigaction". If gdb could assume this, it would simplify this code. gdb/ChangeLog 2019-11-26 Tom Tromey <tom@tromey.com> * event-top.h (thread_local_segv_handler): Declare. * event-top.c (thread_local_segv_handler): New global. (install_handle_sigsegv, handle_sigsegv): New functions. (async_init_signals): Install SIGSEGV handler. * cp-support.c (gdb_demangle_jmp_buf): Change type. Now thread-local. (report_failed_demangle): New function. (gdb_demangle): Make core_dump_allowed atomic. Remove signal handler-setting code, instead use segv_handler. Run warning code on main thread. Change-Id: Ic832bbb033b64744e4b44f14b41db7e4168ce427
Diffstat (limited to 'gdb/event-top.c')
-rw-r--r--gdb/event-top.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 6c6e0ff..9ec599e 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -848,6 +848,45 @@ gdb_readline_no_editing_callback (gdb_client_data client_data)
}
+/* See event-top.h. */
+
+thread_local void (*thread_local_segv_handler) (int);
+
+static void handle_sigsegv (int sig);
+
+/* Install the SIGSEGV handler. */
+static void
+install_handle_sigsegv ()
+{
+#if defined (HAVE_SIGACTION)
+ struct sigaction sa;
+ sa.sa_handler = handle_sigsegv;
+ sigemptyset (&sa.sa_mask);
+#ifdef HAVE_SIGALTSTACK
+ sa.sa_flags = SA_ONSTACK;
+#else
+ sa.sa_flags = 0;
+#endif
+ sigaction (SIGSEGV, &sa, nullptr);
+#else
+ signal (SIGSEGV, handle_sigsegv);
+#endif
+}
+
+/* Handler for SIGSEGV. */
+
+static void
+handle_sigsegv (int sig)
+{
+ install_handle_sigsegv ();
+
+ if (thread_local_segv_handler == nullptr)
+ abort ();
+ thread_local_segv_handler (sig);
+}
+
+
+
/* The serial event associated with the QUIT flag. set_quit_flag sets
this, and check_quit_flag clears it. Used by interruptible_select
to be able to do interruptible I/O with no race with the SIGINT
@@ -915,6 +954,8 @@ async_init_signals (void)
sigtstp_token =
create_async_signal_handler (async_sigtstp_handler, NULL);
#endif
+
+ install_handle_sigsegv ();
}
/* See defs.h. */