From 3b3978bca2a204a772563c8e121e4a02be72e802 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Mon, 4 Mar 2019 15:12:04 -0700 Subject: 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 * 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 --- gdb/event-top.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'gdb/event-top.c') 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. */ -- cgit v1.1