[RFC master/7.12.1] Don't propagate C++ exceptions across readline using SjLj on SjLj-based exception unwinding
Tue Dec 20 16:25:00 GMT 2016
On 12/20/2016 02:33 PM, Yao Qi wrote:
> On 16-12-20 11:49:58, Pedro Alves wrote:
>>> I dig into libcc/unwind-sjlj.c and gcc/except.c, but I still
>>> don't find much clue. This patch fixes this issue by not propagating
>>> the exception via setjmp/longjmp if __USING_SJLJ_EXCEPTIONS__.
>> I think I have a working approach that isn't specific to sjlj
>> exceptions, which I'd prefer. I.e., use "noexcept", to make
>> the compiler understand that the function doesn't throw, and hence
>> doesn't need to issue _Unwind_SjLj_Register / _Unwind_SjLj_Unregister
>> calls. That seems to do the trick. I tried both -O0 and -O2 (with
>> GCC trunk). Does this work for you too?
> Yes, it is better. I wanted to let gcc not to generate
> _Unwind_SjLj_Unregister calls, but I failed to find "noexcept" does
> the trick.
> The patch works for me.
Great, I've applied it to master now, like below. Will apply to
the 7.12 branch in a moment.
>From 2693a26216c329bd7ec2aae7743409f572de4fa5 Mon Sep 17 00:00:00 2001
From: Pedro Alves <email@example.com>
Date: Tue, 20 Dec 2016 15:46:44 +0000
Subject: [PATCH] Fix longjmp across readline w/ --enable-sjlj-exceptions
Nowadays, GDB propagates C++ exceptions across readline using
setjmp/longjmp 89525768cd08 ("Propagate GDB/C++ exceptions across
readline using sj/lj-based TRY/CATCH") because DWARF-based unwinding
can't cross C functions compiled without -fexceptions (see details
from the commit above).
Unfortunately, toolchains that use SjLj-based C++ exceptions got
broken with that fix, because _Unwind_SjLj_Unregister, which is put at
the exit of a function, is not executed due to the longjmp added by
(gdb) [New Thread 2936.0xb80]
Thread 1 received signal SIGSEGV, Segmentation fault.
0x03ff662b in ?? ()
#0 0x03ff662b in ?? ()
#1 0x00526b92 in stdin_event_handler (error=0, client_data=0x172ed8)
#2 0x00525a94 in handle_file_event (ready_mask=<optimized out>,
file_ptr=0x3ff5cb8) at ../../binutils-gdb/gdb/event-loop.c:733
#3 gdb_wait_for_event (block=block@entry=1)
#4 0x00525bfb in gdb_do_one_event ()
#5 0x00525ce5 in start_event_loop ()
#6 0x0051fada in captured_command_loop (data=0x0)
#7 0x0051cf5d in catch_errors (
errstring=errstring@entry=0x7922bf <VEC_interp_factory_p_quick_push(VEC_inte rp_factory_p*, interp_factory*, char const*, unsigned int)::__PRETTY_FUNCTION__+351> "", mask=mask@entry=RETURN_MASK_ALL)
#8 0x00520f0c in captured_main (data=0x328feb4)
#9 gdb_main (args=args@entry=0x328feb4) at ../../binutils-gdb/gdb/main.c:1159
#10 0x0071e400 in main (argc=1, argv=0x171220)
Fix this by making the functions involved in setjmp/longjmp as
noexcept, so that the compiler knows it doesn't need to emit the
_Unwind_SjLj_Register / _Unwind_SjLj_Unregister calls for C++
Tested on x86_64 Fedora 23 with:
- GCC 5.3.1 w/ DWARF-based exceptions.
- GCC 7 built with --enable-sjlj-exceptions.
2016-12-20 Pedro Alves <firstname.lastname@example.org>
Yao Qi <email@example.com>
* event-top.c (gdb_rl_callback_read_char_wrapper_noexcept): New
noexcept function, factored out from ...
(gdb_rl_callback_read_char_wrapper): ... this.
(gdb_rl_callback_handler): Mark noexcept.
gdb/ChangeLog | 9 +++++++++
gdb/event-top.c | 23 ++++++++++++++++++-----
2 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 233a43c..5f0e6fe 100644
@@ -1,3 +1,12 @@
+2016-12-20 Pedro Alves <firstname.lastname@example.org>
+ Yao Qi <email@example.com>
+ PR gdb/20977
+ * event-top.c (gdb_rl_callback_read_char_wrapper_noexcept): New
+ noexcept function, factored out from ...
+ (gdb_rl_callback_read_char_wrapper): ... this.
+ (gdb_rl_callback_handler): Mark noexcept.
2016-12-20 Antoine Tremblay <firstname.lastname@example.org>
* .dir-locals.el: Set c++ mode for the directory and set indent
diff --git a/gdb/event-top.c b/gdb/event-top.c
index acf8474..fa58def 100644
@@ -157,10 +157,12 @@ void (*after_char_processing_hook) (void);
sjlj-based TRY/CATCH mechanism, which knows to handle multiple
levels of active setjmp/longjmp frames, needed in order to handle
the readline callback recursing, as happens with e.g., secondary
- prompts / queries, through gdb_readline_wrapper. */
+ prompts / queries, through gdb_readline_wrapper. This must be
+ noexcept in order to avoid problems with mixing sjlj and
+ (sjlj-based) C++ exceptions. */
-gdb_rl_callback_read_char_wrapper (gdb_client_data client_data)
+static struct gdb_exception
+gdb_rl_callback_read_char_wrapper_noexcept () noexcept
struct gdb_exception gdb_expt = exception_none;
@@ -180,6 +182,15 @@ gdb_rl_callback_read_char_wrapper (gdb_client_data client_data)
+ return gdb_expt;
+gdb_rl_callback_read_char_wrapper (gdb_client_data client_data)
+ struct gdb_exception gdb_expt
+ = gdb_rl_callback_read_char_wrapper_noexcept ();
/* Rethrow using the normal EH mechanism. */
if (gdb_expt.reason < 0)
@@ -187,10 +198,12 @@ gdb_rl_callback_read_char_wrapper (gdb_client_data client_data)
/* GDB's readline callback handler. Calls the current INPUT_HANDLER,
and propagates GDB exceptions/errors thrown from INPUT_HANDLER back
- across readline. See gdb_rl_callback_read_char_wrapper. */
+ across readline. See gdb_rl_callback_read_char_wrapper. This must
+ be noexcept in order to avoid problems with mixing sjlj and
+ (sjlj-based) C++ exceptions. */
-gdb_rl_callback_handler (char *rl)
+gdb_rl_callback_handler (char *rl) noexcept
struct gdb_exception gdb_rl_expt = exception_none;
struct ui *ui = current_ui;
More information about the Gdb-patches