GNU bug report logs - #79318
31.1.90; Threads + receiving a signal causes a segfault

Previous Next

Package: emacs;

Reported by: Spencer Baugh <sbaugh <at> janestreet.com>

Date: Tue, 26 Aug 2025 16:21:02 UTC

Severity: normal

Found in version 31.1.90

To reply to this bug, email your comments to 79318 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#79318; Package emacs. (Tue, 26 Aug 2025 16:21:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Spencer Baugh <sbaugh <at> janestreet.com>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Tue, 26 Aug 2025 16:21:03 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Spencer Baugh <sbaugh <at> janestreet.com>
To: bug-gnu-emacs <at> gnu.org
Subject: 31.1.90; Threads + receiving a signal causes a segfault
Date: Tue, 26 Aug 2025 12:19:07 -0400
repro.el:

(make-thread
 (lambda ()
   (sleep-for .1)
   (signal-process (emacs-pid) 'sigint)))
(sleep-for 100)

emacs -Q -l ./repro.el

Observe Emacs crashes with a segfault while shutting down.

In gdb, the segfault appears to be because current_thread is NULL.

This happens both in 30.2 and on trunk.

bt full:
#0  0x000000000041f32c in Fkill_emacs (arg=arg <at> entry=make_fixnum(2), restart=restart <at> entry=XIL(0)) at emacs.c:3002
        exit_code = <optimized out>
#1  0x000000000041f482 in terminate_due_to_signal (sig=sig <at> entry=2, backtrace_limit=backtrace_limit <at> entry=40) at lisp.h:1226
#2  0x000000000041f8f6 in handle_fatal_signal (sig=sig <at> entry=2) at sysdep.c:1800
#3  0x0000000000557804 in deliver_process_signal (sig=2, handler=0x41f8eb <handle_fatal_signal>) at sysdep.c:1758
        old_errno = 4
        on_main_thread = true
#4  0x00007fffefc12970 in <signal handler called> () at /lib64/libpthread.so.0
#5  0x00007fffec134cd9 in pselect () at /lib64/libc.so.6
#6  0x000000000063b1b0 in really_call_select (arg=0x7fffffffbb80) at thread.c:624
        sa = 0x7fffffffbb80
        self = 0xc77300 <main_thread>
        oldset = {
          __val = {0, 5631674, 1184, 0, 0, 6023007, 6, 5944137, 0, 5635264, 140736988778981, 8, 140737488337912, 13783008, 140737340983936, 6}
        }
#7  0x000000000063bd7e in flush_stack_call_func (arg=0x7fffffffbb80, func=0x63b160 <really_call_select>) at lisp.h:4509
        sa = {
          func = 0x419450 <pselect <at> plt>, 
          max_fds = 6, 
          rfds = 0x7fffffffbc70, 
          wfds = 0x7fffffffbcf0, 
          efds = 0x0, 
          timeout = 0x7fffffffc280, 
          sigmask = 0x0, 
          result = -135497884
        }
#8  0x000000000063bd7e in thread_select (func=<optimized out>, max_fds=max_fds <at> entry=6, rfds=rfds <at> entry=0x7fffffffbc70, wfds=wfds <at> entry=0x7fffffffbcf0, efds=efds <at> entry=0x0, timeout=timeout <at> entry=0x7fffffffc280, sigmask=0x0) at thread.c:656
        sa = {
          func = 0x419450 <pselect <at> plt>, 
          max_fds = 6, 
          rfds = 0x7fffffffbc70, 
          wfds = 0x7fffffffbcf0, 
          efds = 0x0, 
          timeout = 0x7fffffffc280, 
          sigmask = 0x0, 
          result = -135497884
        }
#9  0x0000000000668a3e in xg_select (fds_lim=6, rfds=rfds <at> entry=0x7fffffffc3f0, wfds=wfds <at> entry=0x7fffffffc470, efds=efds <at> entry=0x0, timeout=timeout <at> entry=0x7fffffffc280, sigmask=sigmask <at> entry=0x0) at xgselect.c:184
        all_rfds = {
          fds_bits = {32, 0 <repeats 15 times>}
        }
        all_wfds = {
          fds_bits = {0 <repeats 16 times>}
        }
        tmo = {
          tv_sec = 0, 
          tv_nsec = 0
        }
        tmop = 0x7fffffffc280
        context = 0xdb81a0
        have_wfds = <optimized out>
        gfds_buf = {{
            fd = 5, 
            events = 1, 
            revents = 0
          }, {
            fd = 15393381, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 48, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 6, 
            events = 0, 
            revents = 0
          }, {
            fd = 2, 
            events = 0, 
            revents = 0
          }, {
            fd = 2, 
            events = 0, 
            revents = 0
          }, {
            fd = 2, 
            events = 0, 
            revents = 0
          }, {
            fd = 2, 
            events = 0, 
            revents = 0
          }, {
            fd = -334913767, 
            events = 32767, 
            revents = 0
          }, {
            fd = 15040436, 
            events = 0, 
            revents = 0
          }, {
            fd = -331543520, 
            events = 32767, 
            revents = 0
          }, {
            fd = 6400, 
            events = 0, 
            revents = 0
          }, {
            fd = 1, 
            events = 0, 
            revents = 0
          }, {
            fd = 7, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = -1089891930, 
            events = 65152, 
            revents = 22775
          }, {
            fd = 13945992, 
            events = 0, 
            revents = 0
          }, {
            fd = 6448, 
            events = 0, 
            revents = 0
          }, {
            fd = -440, 
            events = 65535, 
            revents = 65535
          }, {
            fd = 100, 
            events = 0, 
            revents = 0
          }, {
            fd = 103, 
            events = 148, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 103, 
            events = 119, 
            revents = 0
          }, {
            fd = 12, 
            events = 0, 
            revents = 0
          }, {
            fd = 1, 
            events = 0, 
            revents = 0
          }, {
            fd = 124, 
            events = 111, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = -331543616, 
            events = 32767, 
            revents = 0
          }, {
            fd = 6400, 
            events = 0, 
            revents = 0
          }, {
            fd = -440, 
            events = 65535, 
            revents = 65535
          }, {
            fd = 25, 
            events = 0, 
            revents = 0
          }, {
            fd = 80, 
            events = 0, 
            revents = 0
          }, {
            fd = 25, 
            events = 0, 
            revents = 0
          }, {
            fd = -334909086, 
            events = 32767, 
            revents = 0
          }, {
            fd = 6400, 
            events = 0, 
            revents = 0
          }, {
            fd = 6400, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 5873064, 
            events = 0, 
            revents = 0
          }, {
            fd = 3840, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 24, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 25, 
            events = 0, 
            revents = 0
          }, {
            fd = 15398112, 
            events = 0, 
            revents = 0
          }, {
            fd = 5873287, 
            events = 0, 
            revents = 0
          }, {
            fd = 3840, 
            events = 0, 
            revents = 0
          }, {
            fd = 15398096, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 4357902, 
            events = 0, 
            revents = 0
          }, {
            fd = 15397616, 
            events = 0, 
            revents = 0
          }, {
            fd = 321, 
            events = 0, 
            revents = 0
          }, {
            fd = 15397600, 
            events = 0, 
            revents = 0
          }, {
            fd = 25, 
            events = 0, 
            revents = 0
          }, {
            fd = 336, 
            events = 0, 
            revents = 0
          }, {
            fd = -334906405, 
            events = 32767, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = -331543616, 
            events = 32767, 
            revents = 0
          }, {
            fd = -511466344, 
            events = 25, 
            revents = 0
          }, {
            fd = 321, 
            events = 0, 
            revents = 0
          }, {
            fd = 321, 
            events = 0, 
            revents = 0
          }, {
            fd = 1, 
            events = 0, 
            revents = 0
          }, {
            fd = 25, 
            events = 0, 
            revents = 0
          }, {
            fd = 80, 
            events = 0, 
            revents = 0
          }, {
            fd = 1, 
            events = 0, 
            revents = 0
          }, {
            fd = 5872976, 
            events = 0, 
            revents = 0
          }, {
            fd = 80, 
            events = 25, 
            revents = 0
          }, {
            fd = 1, 
            events = 0, 
            revents = 0
          }, {
            fd = 25, 
            events = 0, 
            revents = 0
          }, {
            fd = 14523552, 
            events = 0, 
            revents = 0
          }, {
            fd = 80, 
            events = 25, 
            revents = 0
          }, {
            fd = 4381164, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 4830954, 
            events = 0, 
            revents = 0
          }, {
            fd = 15393376, 
            events = 0, 
            revents = 0
          }, {
            fd = 15393376, 
            events = 2, 
            revents = 0
          }, {
            fd = -16220, 
            events = 32767, 
            revents = 0
          }, {
            fd = 15393376, 
            events = 0, 
            revents = 0
          }, {
            fd = 80, 
            events = 0, 
            revents = 0
          }, {
            fd = 80, 
            events = 0, 
            revents = 0
          }, {
            fd = 25, 
            events = 0, 
            revents = 0
          }, {
            fd = 14523552, 
            events = 0, 
            revents = 0
          }, {
            fd = 80, 
            events = 0, 
            revents = 0
          }, {
            fd = 4409751, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 5, 
            events = 0, 
            revents = 0
          }, {
            fd = 2, 
            events = 0, 
            revents = 0
          }, {
            fd = 538976288, 
            events = 80, 
            revents = 0
          }, {
            fd = 25, 
            events = 80, 
            revents = 0
          }, {
            fd = 2, 
            events = 8224, 
            revents = 8224
          }, {
            fd = 24, 
            events = 0, 
            revents = 0
          }, {
            fd = 1, 
            events = 25, 
            revents = 0
          }, {
            fd = 80, 
            events = 1, 
            revents = 0
          }, {
            fd = 80, 
            events = 0, 
            revents = 256
          }, {
            fd = 0, 
            events = 80, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 25, 
            events = 25, 
            revents = 0
          }, {
            fd = 6457486, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 1, 
            events = 0, 
            revents = 0
          }, {
            fd = 1, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 1, 
            events = 0, 
            revents = 0
          }, {
            fd = 5510312, 
            events = 0, 
            revents = 0
          }, {
            fd = -16048, 
            events = 32767, 
            revents = 0
          }, {
            fd = 13783008, 
            events = 65533, 
            revents = 65535
          }, {
            fd = -512860104, 
            events = 32767, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 37392, 
            events = 0, 
            revents = 0
          }, {
            fd = 14523557, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 5, 
            events = 5, 
            revents = 0
          }, {
            fd = 37392, 
            events = 0, 
            revents = 0
          }, {
            fd = 14523557, 
            events = 0, 
            revents = 0
          }, {
            fd = 48, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 1, 
            events = 0, 
            revents = 0
          }, {
            fd = 1, 
            events = 0, 
            revents = 0
          }, {
            fd = 0, 
            events = 0, 
            revents = 0
          }, {
            fd = 1, 
            events = 0, 
            revents = 0
          }, {
            fd = -15984, 
            events = 32767, 
            revents = 0
          }, {
            fd = -334485062, 
            events = 32767, 
            revents = 0
          }}
        gfds = 0x7fffffffbd70
        gfds_size = <optimized out>
        n_gfds = <optimized out>
        retval = 0
        our_fds = 0
        max_fds = <optimized out>
        i = <optimized out>
        nfds = <optimized out>
        tmo_in_millisec = -1
        must_free = <optimized out>
        need_to_dispatch = <optimized out>
#10 0x00000000006191a3 in wait_reading_process_output (time_limit=time_limit <at> entry=100, nsecs=nsecs <at> entry=0, read_kbd=read_kbd <at> entry=0, do_display=do_display <at> entry=false, wait_for_cell=wait_for_cell <at> entry=XIL(0), wait_proc=wait_proc <at> entry=0x0, just_wait_proc=0) at process.c:5711
        tls_nfds = 0
        tls_available = {
          fds_bits = {0 <repeats 16 times>}
        }
        process_skipped = <optimized out>
        wrapped = <optimized out>
        channel_start = <optimized out>
        child_fd = <optimized out>
        last_read_channel = -1
        channel = <optimized out>
        nfds = <optimized out>
        Available = {
          fds_bits = {0 <repeats 16 times>}
        }
        Writeok = {
          fds_bits = {0 <repeats 16 times>}
        }
        check_write = true
        check_delay = <optimized out>
        no_avail = false
        xerrno = 4
        proc = <optimized out>
        timeout = {
          tv_sec = 99, 
          tv_nsec = 999925830
        }
        end_time = <optimized out>
        timer_delay = <optimized out>
        got_output_end_time = {
          tv_sec = 0, 
          tv_nsec = -1
        }
        wait = TIMEOUT
        got_some_output = -1
        prev_wait_proc_nbytes_read = 0
        retry_for_async = <optimized out>
        now = <optimized out>
#11 0x000000000042788b in Fsleep_for (seconds=<optimized out>, milliseconds=<optimized out>) at lisp.h:1192
        t = {
          tv_sec = 100, 
          tv_nsec = 0
        }
        tend = {
          tv_sec = 1756225164, 
          tv_nsec = 695603177
        }
        duration = <optimized out>
#12 0x00000000005c1f2e in eval_sub (form=<optimized out>) at lisp.h:2243
        i = <optimized out>
        maxargs = 2
        args_left = XIL(0)
        numargs = 1
        original_fun = <optimized out>
        original_args = XIL(0x7ffff73ae593)
        count = {
          bytes = 1024
        }
        fun = <optimized out>
        val = <optimized out>
        funcar = <optimized out>
        argvals = {make_fixnum(100), XIL(0), XIL(0x7fffffffc748), XIL(0x400), make_fixnum(0), XIL(0x400), make_fixnum(0), XIL(0x7fffffffc750)}
#13 0x00000000005ea19a in readevalloop_eager_expand_eval (val=<optimized out>, macroexpand=XIL(0xb340)) at lisp.h:1192
#14 0x00000000005f0dbf in readevalloop (readcharfun=XIL(0xe57515), infile0=0x0, sourcename=XIL(0xe213f4), printflag=false, unibyte=<optimized out>, readfun=XIL(0), start=XIL(0), end=XIL(0)) at lread.c:2548
        c = <optimized out>
        val = XIL(0x7ffff73ae583)
        b = <optimized out>
        continue_reading_p = true
        lex_bound = <optimized out>
        whole_buffer = true
        first_sexp = <optimized out>
        macroexpand = XIL(0xb340)
#15 0x00000000005f2070 in Feval_buffer (buffer=<optimized out>, printflag=XIL(0), filename=XIL(0xe213f4), unibyte=XIL(0), do_allow_print=<optimized out>) at lisp.h:1488
        tem = XIL(0)
        buf = XIL(0xe57515)
#16 0x00007ffff5f1a59e in F6c6f61642d776974682d636f64652d636f6e76657273696f6e_load_with_code_conversion_0 () at /usr/local/home/sbaugh/src/emacs/emacs-30/src/../native-lisp/30.1.90-04e012b0/preloaded/mule-0685467c-3b823856.eln
#17 0x00000000005beba0 in Ffuncall (nargs=nargs <at> entry=5, args=args <at> entry=0x7fffffffcaa0) at eval.c:3097
        val = <optimized out>
#18 0x00000000005f1879 in Fload (file=XIL(0xe210a4), noerror=XIL(0), nomessage=XIL(0x30), nosuffix=<optimized out>, must_suffix=<optimized out>) at lisp.h:1488
        val = <optimized out>
        stream = 0x0
        fd = 5
        found = XIL(0xe213f4)
        efound = <optimized out>
        hist_file_name = <optimized out>
        newer = false
        compiled = false
        handler = <optimized out>
        fmode = 0x6b41e7 "r"
        version = 0
        no_native = false
        is_module = false
        is_native_elisp = false
        found_eff = <optimized out>
        is_elc = false
        input = {
          stream = 0xeed314, 
          lookahead = -92 '\244', 
          buf = "\020\342\000"
        }
#19 0x00007ffff57d56bc in F636f6d6d616e642d6c696e652d31_command_line_1_0 () at /usr/local/home/sbaugh/src/emacs/emacs-30/src/../native-lisp/30.1.90-04e012b0/preloaded/startup-1d646357-21c0c8b9.eln
#20 0x00000000005beba0 in Ffuncall (nargs=2, args=0x7fffffffd080) at eval.c:3097
        val = <optimized out>
#21 0x00007ffff57cd3af in F636f6d6d616e642d6c696e65_command_line_0 () at /usr/local/home/sbaugh/src/emacs/emacs-30/src/../native-lisp/30.1.90-04e012b0/preloaded/startup-1d646357-21c0c8b9.eln
#22 0x00000000005beba0 in Ffuncall (nargs=1, args=0x7fffffffd158) at eval.c:3097
        val = <optimized out>
#23 0x00007ffff57c8bfb in F6e6f726d616c2d746f702d6c6576656c_normal_top_level_0 () at /usr/local/home/sbaugh/src/emacs/emacs-30/src/../native-lisp/30.1.90-04e012b0/preloaded/startup-1d646357-21c0c8b9.eln
#24 0x00000000005c2012 in eval_sub (form=<optimized out>) at lisp.h:2243
        i = 0
        maxargs = <optimized out>
        args_left = XIL(0)
        numargs = 0
        original_fun = <optimized out>
        original_args = XIL(0)
        count = {
          bytes = 128
        }
        fun = <optimized out>
        val = <optimized out>
        funcar = <optimized out>
        argvals = {XIL(0xffffffffffffffff), XIL(0x7fffffffd3b4), XIL(0x7fffffffd3e8), make_fixnum(35184288361560), XIL(0xc77300), XIL(0xe1bb40), XIL(0x7ffff73deb43), make_fixnum(1504411)}
#25 0x00000000005c3b0f in Feval (form=XIL(0x7fffe210eaa3), lexical=lexical <at> entry=XIL(0x30)) at eval.c:2466
#26 0x0000000000537edb in top_level_2 () at lisp.h:1192
        res = <optimized out>
#27 0x00000000005bd532 in internal_condition_case (bfun=bfun <at> entry=0x537e90 <top_level_2>, handlers=handlers <at> entry=XIL(0x90), hfun=hfun <at> entry=0x53f140 <cmd_error>) at eval.c:1617
        val = <optimized out>
        c = 0xe1bb40
#28 0x0000000000539a02 in top_level_1 (ignore=ignore <at> entry=XIL(0)) at lisp.h:1192
#29 0x00000000005bd461 in internal_catch (tag=tag <at> entry=XIL(0x122d0), func=func <at> entry=0x5399e0 <top_level_1>, arg=arg <at> entry=XIL(0)) at eval.c:1296
        val = <optimized out>
        c = 0xef0e00
#30 0x0000000000537dbb in command_loop () at lisp.h:1192
#31 0x000000000053ecf6 in recursive_edit_1 () at keyboard.c:754
        val = <optimized out>
#32 0x000000000053f084 in Frecursive_edit () at keyboard.c:837
        buffer = <optimized out>
#33 0x00000000004267a7 in main (argc=<optimized out>, argv=<optimized out>) at emacs.c:2646
        stack_bottom_variable = 0xc4acf64ff28ad800
        old_argc = <optimized out>
        no_loadup = false
        junk = 0x0
        dname_arg = 0x0
        ch_to_dir = 0x0
        original_pwd = <optimized out>
        dump_mode = <optimized out>
        skip_args = 1
        temacs = 0x0
        attempt_load_pdump = <optimized out>
        only_version = <optimized out>
        rlim = {
          rlim_cur = 10022912, 
          rlim_max = 18446744073709551615
        }
        lc_all = <optimized out>
        sockfd = -1
        module_assertions = <optimized out>




In GNU Emacs 30.1.90 (build 9, x86_64-pc-linux-gnu, X toolkit, cairo
 version 1.15.12, Xaw scroll bars) of 2025-08-14 built on
 igm-qws-u22796a
Repository revision: 6adc26ffa74aedbd1cfa9a1ee72073ebccea2b96
Repository branch: emacs-30
Windowing system distributor 'The X.Org Foundation', version 11.0.12101016
System Description: Rocky Linux 8.10 (Green Obsidian)

Configured using:
 'configure --with-x-toolkit=lucid --without-gpm --without-gconf
 --without-selinux --without-imagemagick --with-modules --with-gif=no
 --with-cairo --with-rsvg --without-compress-install --with-tree-sitter
 --with-native-compilation=aot
 PKG_CONFIG_PATH=/usr/local/home/garnish/libtree-sitter/0.22.6-1/lib/pkgconfig/'

Configured features:
CAIRO DBUS FREETYPE GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG LIBSYSTEMD
LIBXML2 MODULES NATIVE_COMP NOTIFY INOTIFY PDUMPER PNG RSVG SECCOMP
SOUND SQLITE3 THREADS TIFF TOOLKIT_SCROLL_BARS TREE_SITTER X11 XDBE XIM
XINPUT2 XPM LUCID ZLIB

Important settings:
  value of $LANG: en_US.utf8
  locale-coding-system: utf-8-unix




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#79318; Package emacs. (Tue, 26 Aug 2025 18:46:01 GMT) Full text and rfc822 format available.

Message #8 received at 79318 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Spencer Baugh <sbaugh <at> janestreet.com>,
 Paul Eggert <eggert <at> cs.ucla.edu>
Cc: 79318 <at> debbugs.gnu.org
Subject: Re: bug#79318: 31.1.90; Threads + receiving a signal causes a segfault
Date: Tue, 26 Aug 2025 21:45:03 +0300
> Date: Tue, 26 Aug 2025 12:19:07 -0400
> From:  Spencer Baugh via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
> 
> 
> repro.el:
> 
> (make-thread
>  (lambda ()
>    (sleep-for .1)
>    (signal-process (emacs-pid) 'sigint)))
> (sleep-for 100)
> 
> emacs -Q -l ./repro.el
> 
> Observe Emacs crashes with a segfault while shutting down.

I don't see a segfault in your backtrace, only a shutdown due to
SIGINT (which is a fatal signal in the configuration you ran -- Paul,
am I right?)

> In gdb, the segfault appears to be because current_thread is NULL.

Please show the backtrace from the segfault.  What you posted was a
SIGINT that caused shutdown, which seems to be normal (in the GUI
session on X).  On Windows and in -nw session, there's no shutdown.

Why is this case interesting?  When delivering a fatal signal to the
own Emacs process, a fatal error and a shutdown should not come as a
surprise, right?  Or what am I missing?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#79318; Package emacs. (Tue, 26 Aug 2025 19:24:01 GMT) Full text and rfc822 format available.

Message #11 received at 79318 <at> debbugs.gnu.org (full text, mbox):

From: Spencer Baugh <sbaugh <at> janestreet.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 79318 <at> debbugs.gnu.org, Paul Eggert <eggert <at> cs.ucla.edu>
Subject: Re: bug#79318: 31.1.90; Threads + receiving a signal causes a segfault
Date: Tue, 26 Aug 2025 15:23:20 -0400
Eli Zaretskii <eliz <at> gnu.org> writes:

>> Date: Tue, 26 Aug 2025 12:19:07 -0400
>> From:  Spencer Baugh via "Bug reports for GNU Emacs,
>>  the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
>> 
>> 
>> repro.el:
>> 
>> (make-thread
>>  (lambda ()
>>    (sleep-for .1)
>>    (signal-process (emacs-pid) 'sigint)))
>> (sleep-for 100)
>> 
>> emacs -Q -l ./repro.el
>> 
>> Observe Emacs crashes with a segfault while shutting down.
>
> I don't see a segfault in your backtrace, only a shutdown due to
> SIGINT (which is a fatal signal in the configuration you ran -- Paul,
> am I right?)

The backtrace is of the point at which there's a segfault.  It happens
during shutdown.

>> In gdb, the segfault appears to be because current_thread is NULL.
>
> Please show the backtrace from the segfault.

I did.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#79318; Package emacs. (Wed, 27 Aug 2025 02:27:02 GMT) Full text and rfc822 format available.

Message #14 received at 79318 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Spencer Baugh <sbaugh <at> janestreet.com>
Cc: 79318 <at> debbugs.gnu.org, eggert <at> cs.ucla.edu
Subject: Re: bug#79318: 31.1.90; Threads + receiving a signal causes a segfault
Date: Wed, 27 Aug 2025 05:26:37 +0300
> From: Spencer Baugh <sbaugh <at> janestreet.com>
> Cc: Paul Eggert <eggert <at> cs.ucla.edu>,  79318 <at> debbugs.gnu.org
> Date: Tue, 26 Aug 2025 15:23:20 -0400
> 
> Eli Zaretskii <eliz <at> gnu.org> writes:
> 
> >> Date: Tue, 26 Aug 2025 12:19:07 -0400
> >> From:  Spencer Baugh via "Bug reports for GNU Emacs,
> >>  the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
> >> 
> >> 
> >> repro.el:
> >> 
> >> (make-thread
> >>  (lambda ()
> >>    (sleep-for .1)
> >>    (signal-process (emacs-pid) 'sigint)))
> >> (sleep-for 100)
> >> 
> >> emacs -Q -l ./repro.el
> >> 
> >> Observe Emacs crashes with a segfault while shutting down.
> >
> > I don't see a segfault in your backtrace, only a shutdown due to
> > SIGINT (which is a fatal signal in the configuration you ran -- Paul,
> > am I right?)
> 
> The backtrace is of the point at which there's a segfault.  It happens
> during shutdown.
> 
> >> In gdb, the segfault appears to be because current_thread is NULL.
> >
> > Please show the backtrace from the segfault.
> 
> I did.

Such a backtrace should say that the process was hit by SIGSEGV.
There was no such part in the backtrace you have shown.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#79318; Package emacs. (Wed, 27 Aug 2025 05:08:01 GMT) Full text and rfc822 format available.

Message #17 received at 79318 <at> debbugs.gnu.org (full text, mbox):

From: Spencer Baugh <sbaugh <at> janestreet.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 79318 <at> debbugs.gnu.org, eggert <at> cs.ucla.edu
Subject: Re: bug#79318: 31.1.90; Threads + receiving a signal causes a segfault
Date: Wed, 27 Aug 2025 01:07:17 -0400
[Message part 1 (text/plain, inline)]
On Tue, Aug 26, 2025, 10:26 PM Eli Zaretskii <eliz <at> gnu.org> wrote:

> > From: Spencer Baugh <sbaugh <at> janestreet.com>
> > Cc: Paul Eggert <eggert <at> cs.ucla.edu>,  79318 <at> debbugs.gnu.org
> > Date: Tue, 26 Aug 2025 15:23:20 -0400
> >
> > Eli Zaretskii <eliz <at> gnu.org> writes:
> >
> > >> Date: Tue, 26 Aug 2025 12:19:07 -0400
> > >> From:  Spencer Baugh via "Bug reports for GNU Emacs,
> > >>  the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
> > >>
> > >>
> > >> repro.el:
> > >>
> > >> (make-thread
> > >>  (lambda ()
> > >>    (sleep-for .1)
> > >>    (signal-process (emacs-pid) 'sigint)))
> > >> (sleep-for 100)
> > >>
> > >> emacs -Q -l ./repro.el
> > >>
> > >> Observe Emacs crashes with a segfault while shutting down.
> > >
> > > I don't see a segfault in your backtrace, only a shutdown due to
> > > SIGINT (which is a fatal signal in the configuration you ran -- Paul,
> > > am I right?)
> >
> > The backtrace is of the point at which there's a segfault.  It happens
> > during shutdown.
> >
> > >> In gdb, the segfault appears to be because current_thread is NULL.
> > >
> > > Please show the backtrace from the segfault.
> >
> > I did.
>
> Such a backtrace should say that the process was hit by SIGSEGV.
> There was no such part in the backtrace you have shown.
>

My version of gdb does not.

>
[Message part 2 (text/html, inline)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#79318; Package emacs. (Wed, 27 Aug 2025 12:30:02 GMT) Full text and rfc822 format available.

Message #20 received at 79318 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: eggert <at> cs.ucla.edu, Spencer Baugh <sbaugh <at> janestreet.com>
Cc: 79318 <at> debbugs.gnu.org
Subject: Re: bug#79318: 31.1.90; Threads + receiving a signal causes a segfault
Date: Wed, 27 Aug 2025 15:29:35 +0300
> From: Spencer Baugh <sbaugh <at> janestreet.com>
> Date: Wed, 27 Aug 2025 01:07:17 -0400
> Cc: eggert <at> cs.ucla.edu, 79318 <at> debbugs.gnu.org
> 
>  > > Please show the backtrace from the segfault.
>  > 
>  > I did.
> 
>  Such a backtrace should say that the process was hit by SIGSEGV.
>  There was no such part in the backtrace you have shown.
> 
> My version of gdb does not.

OK, never mind, that.

I think this bug report raises a much more general issue than what the
recipe shows: what happens when a Lisp thread gets delivered a fatal
signal when it doesn't own the global lock?

This could happen in at least two cases:

 . the signal is delivered to the main thread (as AFAIU it happens on
   GNU/Linux and some other systems) when the current thread is some
   other thread
 . the signal is delivered to the main thread while the main thread is
   stuck in some wait before it obtained the global lock, and the
   other threads all exited (like in the scenario you presented)

The important aspect here is that the signal handler runs in the
context of a thread that doesn't have the global lock, so it cannot
run Lisp or the Lisp machine safely.  However, calling kill-emacs, as
part of an attempt to shut down Emacs in an orderly fashion, can and
does run Lisp.

AFAICT, we don't currently have a solution for this situation.

We could do several things:

  . do nothing, and let kill-emacs crash if it must -- after all, the
    attempt at an orderly shut down is known to fail in some cases
  . override attempt-orderly-shutdown-on-fatal-signal in such cases
    and just call shutdown_emacs (losing some of the session as
    result)
  . somehow attempt to force the thread holding the global lock to
    relinquish it, so that the main thread could take the lock, and
    then call kill-emacs

If we decide to go with the last idea, we need to discuss how to
obtain the lock, it is not trivial, let alone portable.

Paul, when a fatal signal is delivered to Emacs from outside, it goes
to the main thread, but what happens with other threads? do they keep
running as before, or do they stop?

And what about "synchronous" signals like SIGSEGV -- if a non-main
thread triggers such a signal, does the handler run in that thread, or
does it run in the main thread?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#79318; Package emacs. (Wed, 27 Aug 2025 15:32:01 GMT) Full text and rfc822 format available.

Message #23 received at 79318 <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: Eli Zaretskii <eliz <at> gnu.org>, Spencer Baugh <sbaugh <at> janestreet.com>
Cc: 79318 <at> debbugs.gnu.org
Subject: Re: bug#79318: 31.1.90; Threads + receiving a signal causes a segfault
Date: Wed, 27 Aug 2025 08:31:18 -0700
On 2025-08-27 05:29, Eli Zaretskii wrote:
> Paul, when a fatal signal is delivered to Emacs from outside, it goes
> to the main thread, but what happens with other threads? do they keep
> running as before, or do they stop?

Those fatal signals go to the main thread because if the OS delivers 
them elsewhere, Emacs uses pthread_kill to redeliver them to the main 
thread. In this situation the thread that originally got the signal is 
suspended. All other threads keep running.

I suppose it's possible that the thread that originally got the signal 
is not the main thread, and owns the global lock. If this is the case, 
then either the shutdown code should not need to acquire the global 
lock, or the thread that originally got the signal should release the 
global lock in a safe way. As I recall, when this signal stuff was 
written there was no global lock, so perhaps when the global lock was 
added the possibility that I describe was not considered.


> And what about "synchronous" signals like SIGSEGV -- if a non-main
> thread triggers such a signal, does the handler run in that thread, or
> does it run in the main thread?

It depends on the signal. A SIGSEGV is considered to be fatal if garbage 
collection is in progress, if it is triggered in a non-main thread, or 
if Emacs thinks that it was not caused by stack overflow. A non-fatal 
SIGSEGV causes Emacs to longjmp back to the top level command loop; 
other threads keep running. A fatal SIGSEGV is handled as described above.

The full story is a more complicated on Android and on MS-Windows. It's 
not clear from the bug report which platform we're talking about, but I 
suspect it's not MS-Windows (where you're the expert and wouldn't need 
to ask me) or Android.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#79318; Package emacs. (Wed, 27 Aug 2025 16:46:01 GMT) Full text and rfc822 format available.

Message #26 received at 79318 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Paul Eggert <eggert <at> cs.ucla.edu>
Cc: sbaugh <at> janestreet.com, 79318 <at> debbugs.gnu.org
Subject: Re: bug#79318: 31.1.90; Threads + receiving a signal causes a segfault
Date: Wed, 27 Aug 2025 19:44:59 +0300
> Date: Wed, 27 Aug 2025 08:31:18 -0700
> Cc: 79318 <at> debbugs.gnu.org
> From: Paul Eggert <eggert <at> cs.ucla.edu>
> 
> On 2025-08-27 05:29, Eli Zaretskii wrote:
> > Paul, when a fatal signal is delivered to Emacs from outside, it goes
> > to the main thread, but what happens with other threads? do they keep
> > running as before, or do they stop?
> 
> Those fatal signals go to the main thread because if the OS delivers 
> them elsewhere, Emacs uses pthread_kill to redeliver them to the main 
> thread. In this situation the thread that originally got the signal is 
> suspended. All other threads keep running.
> 
> I suppose it's possible that the thread that originally got the signal 
> is not the main thread, and owns the global lock. If this is the case, 
> then either the shutdown code should not need to acquire the global 
> lock, or the thread that originally got the signal should release the 
> global lock in a safe way. As I recall, when this signal stuff was 
> written there was no global lock, so perhaps when the global lock was 
> added the possibility that I describe was not considered.

Yes, I think we should do something like that in
deliver_thread_signal.

> > And what about "synchronous" signals like SIGSEGV -- if a non-main
> > thread triggers such a signal, does the handler run in that thread, or
> > does it run in the main thread?
> 
> It depends on the signal. A SIGSEGV is considered to be fatal if garbage 
> collection is in progress, if it is triggered in a non-main thread, or 
> if Emacs thinks that it was not caused by stack overflow. A non-fatal 
> SIGSEGV causes Emacs to longjmp back to the top level command loop; 
> other threads keep running. A fatal SIGSEGV is handled as described above.

OK, thanks.

> The full story is a more complicated on Android and on MS-Windows. It's 
> not clear from the bug report which platform we're talking about, but I 
> suspect it's not MS-Windows (where you're the expert and wouldn't need 
> to ask me) or Android.

No, it wasn't on Windows, indeed.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#79318; Package emacs. (Wed, 27 Aug 2025 16:52:03 GMT) Full text and rfc822 format available.

Message #29 received at 79318 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: eggert <at> cs.ucla.edu
Cc: sbaugh <at> janestreet.com, 79318 <at> debbugs.gnu.org
Subject: Re: bug#79318: 31.1.90; Threads + receiving a signal causes a segfault
Date: Wed, 27 Aug 2025 19:51:16 +0300
> Cc: sbaugh <at> janestreet.com, 79318 <at> debbugs.gnu.org
> Date: Wed, 27 Aug 2025 19:44:59 +0300
> From: Eli Zaretskii <eliz <at> gnu.org>
> 
> > Date: Wed, 27 Aug 2025 08:31:18 -0700
> > Cc: 79318 <at> debbugs.gnu.org
> > From: Paul Eggert <eggert <at> cs.ucla.edu>
> > 
> > On 2025-08-27 05:29, Eli Zaretskii wrote:
> > > Paul, when a fatal signal is delivered to Emacs from outside, it goes
> > > to the main thread, but what happens with other threads? do they keep
> > > running as before, or do they stop?
> > 
> > Those fatal signals go to the main thread because if the OS delivers 
> > them elsewhere, Emacs uses pthread_kill to redeliver them to the main 
> > thread. In this situation the thread that originally got the signal is 
> > suspended. All other threads keep running.
> > 
> > I suppose it's possible that the thread that originally got the signal 
> > is not the main thread, and owns the global lock. If this is the case, 
> > then either the shutdown code should not need to acquire the global 
> > lock, or the thread that originally got the signal should release the 
> > global lock in a safe way. As I recall, when this signal stuff was 
> > written there was no global lock, so perhaps when the global lock was 
> > added the possibility that I describe was not considered.
> 
> Yes, I think we should do something like that in
> deliver_thread_signal.

Actually, one more question about that: didn't you tell me at some
point that on GNU/Linux the OS takes care of delivering fatal signals
to the main thread?  If that is so, then we have no control on what
happens with the global lock in this case, because
deliver_thread_signal is bypassed, and we might find ourselves in the
situation whereby a non-main thread was running some Lisp, then
triggered a fatal signal or some external source delivered a fatal
signal, and the OS runs the signal handler on the main thread which
doesn't own the global lock.  Is this possible?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#79318; Package emacs. (Wed, 27 Aug 2025 18:12:03 GMT) Full text and rfc822 format available.

Message #32 received at 79318 <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: sbaugh <at> janestreet.com, 79318 <at> debbugs.gnu.org
Subject: Re: bug#79318: 31.1.90; Threads + receiving a signal causes a segfault
Date: Wed, 27 Aug 2025 11:11:34 -0700
On 2025-08-27 09:51, Eli Zaretskii wrote:
> didn't you tell me at some
> point that on GNU/Linux the OS takes care of delivering fatal signals
> to the main thread?

What I recall saying long ago is pretty much what I wrote earlier today, 
namely that if a fatal signal is delivered to a non-main thread, Emacs 
code in the non-main thread arranges to redeliver the signal to the main 
thread.

  If that is so, then we have no control on what
> happens with the global lock in this case, because
> deliver_thread_signal is bypassed, and we might find ourselves in the
> situation whereby a non-main thread was running some Lisp, then
> triggered a fatal signal or some external source delivered a fatal
> signal, and the OS runs the signal handler on the main thread which
> doesn't own the global lock.  Is this possible?

Sounds like it, yes. It could also happen if the kernel decides to 
deliver the externally-sourced signal to the main thread in the first 
place. POSIX allows this.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#79318; Package emacs. (Wed, 27 Aug 2025 18:20:02 GMT) Full text and rfc822 format available.

Message #35 received at 79318 <at> debbugs.gnu.org (full text, mbox):

From: Spencer Baugh <sbaugh <at> janestreet.com>
To: Paul Eggert <eggert <at> cs.ucla.edu>
Cc: Eli Zaretskii <eliz <at> gnu.org>, 79318 <at> debbugs.gnu.org
Subject: Re: bug#79318: 31.1.90; Threads + receiving a signal causes a segfault
Date: Wed, 27 Aug 2025 14:19:19 -0400
Paul Eggert <eggert <at> cs.ucla.edu> writes:
> On 2025-08-27 09:51, Eli Zaretskii wrote:
>> If that is so, then we have no control on what
>> happens with the global lock in this case, because
>> deliver_thread_signal is bypassed, and we might find ourselves in the
>> situation whereby a non-main thread was running some Lisp, then
>> triggered a fatal signal or some external source delivered a fatal
>> signal, and the OS runs the signal handler on the main thread which
>> doesn't own the global lock.  Is this possible?
>
> Sounds like it, yes. It could also happen if the kernel decides to
> deliver the externally-sourced signal to the main thread in the first
> place. POSIX allows this.

Perhaps we could change to deliver signals to whatever thread currently
holds the lock, instead of to the main thread.





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#79318; Package emacs. (Wed, 27 Aug 2025 18:35:02 GMT) Full text and rfc822 format available.

Message #38 received at 79318 <at> debbugs.gnu.org (full text, mbox):

From: Paul Eggert <eggert <at> cs.ucla.edu>
To: Spencer Baugh <sbaugh <at> janestreet.com>
Cc: Eli Zaretskii <eliz <at> gnu.org>, 79318 <at> debbugs.gnu.org
Subject: Re: bug#79318: 31.1.90; Threads + receiving a signal causes a segfault
Date: Wed, 27 Aug 2025 11:34:27 -0700
On 2025-08-27 11:19, Spencer Baugh wrote:
> Perhaps we could change to deliver signals to whatever thread currently
> holds the lock, instead of to the main thread.

Something like that might work, but it's tricky. First, how do you 
determine (in a thread-safe way) whether some other thread holds the 
lock and if so, which thread, and if so, how to signal that thread 
before it gives up its lock or exits? Second, even if you hold the lock, 
how do you finish out your critical section without corrupting the state 
and without introducing other possibilities for hanging?

I'm glad someone *else* will write all that code....




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#79318; Package emacs. (Wed, 27 Aug 2025 19:23:02 GMT) Full text and rfc822 format available.

Message #41 received at 79318 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Paul Eggert <eggert <at> cs.ucla.edu>
Cc: sbaugh <at> janestreet.com, 79318 <at> debbugs.gnu.org
Subject: Re: bug#79318: 31.1.90; Threads + receiving a signal causes a segfault
Date: Wed, 27 Aug 2025 22:22:09 +0300
> Date: Wed, 27 Aug 2025 11:11:34 -0700
> Cc: sbaugh <at> janestreet.com, 79318 <at> debbugs.gnu.org
> From: Paul Eggert <eggert <at> cs.ucla.edu>
> 
> On 2025-08-27 09:51, Eli Zaretskii wrote:
> > didn't you tell me at some
> > point that on GNU/Linux the OS takes care of delivering fatal signals
> > to the main thread?
> 
> What I recall saying long ago is pretty much what I wrote earlier today, 
> namely that if a fatal signal is delivered to a non-main thread, Emacs 
> code in the non-main thread arranges to redeliver the signal to the main 
> thread.
> 
>    If that is so, then we have no control on what
> > happens with the global lock in this case, because
> > deliver_thread_signal is bypassed, and we might find ourselves in the
> > situation whereby a non-main thread was running some Lisp, then
> > triggered a fatal signal or some external source delivered a fatal
> > signal, and the OS runs the signal handler on the main thread which
> > doesn't own the global lock.  Is this possible?
> 
> Sounds like it, yes. It could also happen if the kernel decides to 
> deliver the externally-sourced signal to the main thread in the first 
> place. POSIX allows this.

OK, thanks.  So we still need to have some device in place for if and
when that happens, if we want to be able to run Lisp from the signal
handler.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#79318; Package emacs. (Wed, 27 Aug 2025 19:24:02 GMT) Full text and rfc822 format available.

Message #44 received at 79318 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Spencer Baugh <sbaugh <at> janestreet.com>
Cc: 79318 <at> debbugs.gnu.org, eggert <at> cs.ucla.edu
Subject: Re: bug#79318: 31.1.90; Threads + receiving a signal causes a segfault
Date: Wed, 27 Aug 2025 22:23:14 +0300
> From: Spencer Baugh <sbaugh <at> janestreet.com>
> Cc: Eli Zaretskii <eliz <at> gnu.org>,  79318 <at> debbugs.gnu.org
> Date: Wed, 27 Aug 2025 14:19:19 -0400
> 
> Paul Eggert <eggert <at> cs.ucla.edu> writes:
> > On 2025-08-27 09:51, Eli Zaretskii wrote:
> >> If that is so, then we have no control on what
> >> happens with the global lock in this case, because
> >> deliver_thread_signal is bypassed, and we might find ourselves in the
> >> situation whereby a non-main thread was running some Lisp, then
> >> triggered a fatal signal or some external source delivered a fatal
> >> signal, and the OS runs the signal handler on the main thread which
> >> doesn't own the global lock.  Is this possible?
> >
> > Sounds like it, yes. It could also happen if the kernel decides to
> > deliver the externally-sourced signal to the main thread in the first
> > place. POSIX allows this.
> 
> Perhaps we could change to deliver signals to whatever thread currently
> holds the lock, instead of to the main thread.

If that works reliably, yes, that's a possibility.




This bug report was last modified 10 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.