Subject: bug#76970: 31.0.50; master emacs crash with stack overflow

From: Aaron Zeng <[email-masked]>
Date: Tue, 17 Jun 2025 18:38:26 -0400

I'd like to report that users at my site have seen this crash occur
quite a few times recently, although not necessarily ending in a
stack_overflow() frame (instead usually ending in backtrace_top()).

For us, we believe the incidence was increased by enabling
global-diff-hl-mode (with diff-hl-update-async set to t, so that it
uses threads).  If the Lisp profiler is running and SIGPROF happens to
be delivered while current_thread is NULL, then the following code in
backtrace_top will cause a segfault:

    union specbinding *
    backtrace_top (void)
    {
      /* This is so "xbacktrace" doesn't crash in pdumped Emacs if they
         invoke the command before init_eval_once_for_pdumper initializes
         specpdl machinery.  See also backtrace_p above.  */
      if (!specpdl)                 /* HERE!!! */
        return NULL;

add_sample (profiler.c) is called from a signal handler and therefore
needs to be robust in the case where a thread has just died and there
is no current thread, so it cannot blindly read specpdl.

Here is a full backtrace that I managed to reproduce once.  Emacs was
built at commit 31bac0d68c08f3f2fb03fa6ded17b771b168353e.
Unfortunately, getting a completely reliable reproduction has proved
tricky.

emacs -Q
M-x package-initialize
M-: (setopt diff-hl-update-async t)
M-x global-diff-hl-mode
... and then visiting some files under version control

(gdb) bt full
#0  0x00000000005564f7 in stack_overflow (siginfo=0xcbeb30 <sigsegv_stack+62896>) at sysdep.c:1902
        addr = 0x70 <error: Cannot access memory at address 0x70>
        bot = <optimized out>
        top = <optimized out>
        fatal = false
#1  0x00000000005564f7 in handle_sigsegv (sig=11, siginfo=0xcbeb30 <sigsegv_stack+62896>, arg=<optimized out>) at sysdep.c:1937
        fatal = false
#2  0x00007fbda4812970 in <signal handler called> () at /lib64/libpthread.so.0
#3  0x00000000005c3f27 in backtrace_top () at eval.c:4294
        pdl = <optimized out>
        pdl = <optimized out>
#4  0x00000000005c3f27 in backtrace_top_function () at eval.c:4294
        pdl = <optimized out>
#5  0x000000000063a0da in add_sample (plog=0xcdf060 <cpu>, count=1436) at lisp.h:1192
#6  0x0000000000557604 in deliver_process_signal (sig=27, handler=0x63a440 <handle_profiler_signal>) at sysdep.c:1758
        old_errno = 11
        on_main_thread = true
#7  0x00007fbda4812970 in <signal handler called> () at /lib64/libpthread.so.0
#8  0x00007fbda481154a in __lll_unlock_wake () at /lib64/libpthread.so.0
#9  0x00007fbda480c2e6 in __pthread_mutex_unlock_usercnt () at /lib64/libpthread.so.0
#10 0x000000000063af2f in release_global_lock () at thread.c:621
        sa = 0x7ffc6645abd0
        self = 0xc76300 <main_thread>
        oldset = {__val = {0, 0, 843691369, 843691368, 843691369, 843691368, 0, 837799220, 0, 1, 13385680, 13385744, 0, 0, 13385680, 13385744}}
#11 0x000000000063af2f in really_call_select (arg=0x7ffc6645abd0) at thread.c:621
        sa = 0x7ffc6645abd0
        self = 0xc76300 <main_thread>
        oldset = {__val = {0, 0, 843691369, 843691368, 843691369, 843691368, 0, 837799220, 0, 1, 13385680, 13385744, 0, 0, 13385680, 13385744}}
#12 0x000000000063bb1e in flush_stack_call_func (arg=0x7ffc6645abd0, func=0x63af00 <really_call_select>) at lisp.h:4509
        sa = 
          {func = 0x419450 <pselect@plt>, max_fds = 16, rfds = 0x7ffc6645acc0, wfds = 0x7ffc6645ad40, efds = 0x0, timeout = 0x7ffc6645b2d0, sigmask = 0x0, result = -1756783244}
#13 0x000000000063bb1e in thread_select
    (func=<optimized out>, max_fds=max_fds@entry=16, rfds=rfds@entry=0x7ffc6645acc0, wfds=wfds@entry=0x7ffc6645ad40, efds=efds@entry=0x0, timeout=timeout@entry=0x7ffc6645b2d0, sigmask=0x0) at thread.c:656
        sa = 
          {func = 0x419450 <pselect@plt>, max_fds = 16, rfds = 0x7ffc6645acc0, wfds = 0x7ffc6645ad40, efds = 0x0, timeout = 0x7ffc6645b2d0, sigmask = 0x0, result = -1756783244}
#14 0x00000000006687ae in xg_select
    (fds_lim=16, rfds=rfds@entry=0x7ffc6645b440, wfds=wfds@entry=0x7ffc6645b4c0, efds=efds@entry=0x0, timeout=timeout@entry=0x7ffc6645b2d0, sigmask=sigmask@entry=0x0) at xgselect.c:184
        all_rfds = {fds_bits = {32872, 0 <repeats 15 times>}}
        all_wfds = {fds_bits = {0 <repeats 16 times>}}
        tmo = {tv_sec = 843691368, tv_nsec = 0}
        tmop = 0x7ffc6645b2d0
        context = 0x30c3c7c0
        have_wfds = <optimized out>
        gfds_buf = 
            {{fd = 6, events = 1, revents = 0}, {fd = 20, events = 0, revents = 0}, {fd = 838180836, events = 0, revents = 0}, {fd = 1, 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 = 1, events = 0, revents = 0}, {fd = 843421012, events = 0, revents = 0}, {fd = 28, events = 0, revents = 0}, {fd = 1715839064, events = 32764, revents = 0}, {fd = 6398880, events = 0, revents = 0}, {fd = 1715839040, events = 32764, revents = 0}, {fd = 0, events = 0, revents = 0}, {fd = 0, events = 0, revents = 0}, {fd = 837799222, events = 0, revents = 0}, {fd = 0, events = 0, revents = 0}, {fd = 838180836, events = 0, revents = 0}, {fd = -1547505218, events = 32701, revents = 0}, {fd = 838180836, events = 0, revents = 0}, {fd = 0, events = 42256, revents = 59604}, {fd = 1715843008, events = 32764, revents = 0}, {fd = 838931840, events = 0, revents = 0}, {fd = -40, events = 0, revents = 0}, {fd = 1, events = 0, revents = 0}, {fd = 1715842976, events = 32764, revents = 0}, {fd = 2, events = 0, revents = 0}, {fd = 1715843168, events = 32764, revents = 0}, {fd = -1547358463, events = 32701, revents = 0}, {fd = 13385680, events = 0, revents = 0}, {fd = 13385744, events = 0, revents = 0}, {fd = 0, events = 0, revents = 0}, {fd = 838180808, events = 0, revents = 0}, {fd = 2, events = 0, revents = 0}, {fd = 1715842936, events = 32764, revents = 0}, {fd = 0, events = 0, revents = 0}, {fd = 800, events = 0, revents = 0}, {fd = 2, events = 0, revents = 0}, {fd = 1715842928, events = 32764, revents = 0}, {fd = 1715842936, events = 32764, revents = 0}, {fd = 31536, events = 0, revents = 0}, {fd = 800, events = 0, revents = 0}, {fd = 6023312, events = 0, revents = 0}, {fd = 1, events = 0, revents = 0}, {fd = 0, events = 0, revents = 0}, {fd = 1715843168, events = 32764, revents = 0}, {fd = 838931840, events = 0, revents = 0}, {fd = 835827600, events = 0, revents = 0}, {fd = -1419453425, events = 32701, revents = 0}, {fd --Type <RET> for more, q to quit, c to continue without paging--c
= 20, events = 0, revents = 0}, {fd = 13397248, events = 0, revents = 0}, {fd = 843393045, events = 0, revents = 0}, {fd = -900935680, events = 56540, revents = 24937}, {fd = 31536, events = 0, revents = 0}, {fd = 1, events = 0, revents = 0}, {fd = 2, events = 0, revents = 0}, {fd = 1715843168, events = 32764, revents = 0}, {fd = 13831584, events = 0, revents = 0}, {fd = 1715843216, events = 32764, revents = 0}, {fd = 1715843152, events = 32764, revents = 0}, {fd = -1547525380, events = 32701, revents = 0}, {fd = 1, events = 0, revents = 0}, {fd = -1547524967, events = 32701, revents = 0}, {fd = -1143734272, events = 13752, revents = 50873}, {fd = 6, events = 0, revents = 0}, {fd = 48, events = 0, revents = 0}, {fd = 4511648, events = 0, revents = 0}, {fd = 2, events = 0, revents = 0}, {fd = 836797584, events = 0, revents = 0}, {fd = 2, events = 0, revents = 0}, {fd = 2, events = 0, revents = 0}, {fd = 1, events = 2, revents = 0}, {fd = 838931840, events = 0, revents = 0}, {fd = 0, events = 0, revents = 0}, {fd = -900935680, events = 56540, revents = 24937}, {fd = 0, events = 0, revents = 0}, {fd = 13831584, events = 0, revents = 0}, {fd = 2, events = 0, revents = 0}, {fd = 1, events = 0, revents = 0}, {fd = 13831584, events = 0, revents = 0}, {fd = -1547505218, events = 32701, revents = 0}, {fd = 1715843280, events = 32764, revents = 0}, {fd = 0, events = 10240, revents = 61035}, {fd = 838931840, events = 0, revents = 0}, {fd = 838931832, events = 0, revents = 0}, {fd = -30, events = 0, revents = 0}, {fd = 1, events = 0, revents = 0}, {fd = 1, events = 0, revents = 0}, {fd = 13831584, events = 0, revents = 0}, {fd = 838931840, events = 0, revents = 0}, {fd = -1547572342, events = 32701, revents = 0}, {fd = 838468288, events = 0, revents = 0}, {fd = -727379968, events = 232, revents = 0}, {fd = 818666165, events = 0, revents = 0}, {fd = 5612100, events = 0, revents = 0}, {fd = 125000000, events = 0, revents = 0}, {fd = 818666165, events = 0, revents = 0}, {fd = 52961, events = 0, revents = 0}, {fd = 6444207, events = 0, revents = 0}, {fd = 0, events = 0, revents = 0}, {fd = 0, events = 0, revents = 0}, {fd = 1715843456, events = 32764, revents = 0}, {fd = 6450379, events = 0, revents = 0}, {fd = 1783793666, events = 116, revents = 0}, {fd = 1385447426, events = 931, revents = 0}, {fd = 837309808, events = 0, revents = 0}, {fd = 5510319, events = 0, revents = 0}, {fd = 1056964608, events = 0, revents = 16384}, {fd = 5946044, events = 65281, revents = 65535}, {fd = -1778304512, events = 32701, revents = 0}, {fd = 0, events = 0, revents = 0}, {fd = 0, events = 0, revents = 0}, {fd = 1750195774, events = 0, revents = 0}, {fd = 219655029, events = 0, revents = 0}, {fd = 0, events = 0, revents = 0}, {fd = 837309811, events = 0, revents = 0}, {fd = 5, events = 0, revents = 0}, {fd = 817673880, events = 0, revents = 0}, {fd = 4848413, events = 0, revents = 0}, {fd = 0, events = 0, revents = 0}, {fd = 125000000, events = 0, revents = 0}, {fd = 37, events = 0, revents = 0}, {fd = 836738800, events = 0, revents = 0}, {fd = 0, events = 0, revents = 0}, {fd = 836738800, events = 0, revents = 0}, {fd = 1715843552, events = 32764, revents = 0}, {fd = 5511222, events = 0, revents = 0}}
        gfds = 0x7ffc6645adc0
        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>
#15 0x0000000000619058 in wait_reading_process_output (time_limit=time_limit@entry=37, nsecs=nsecs@entry=0, read_kbd=read_kbd@entry=-1, do_display=do_display@entry=true, wait_for_cell=wait_for_cell@entry=0x0, wait_proc=wait_proc@entry=0x0, just_wait_proc=0) at process.c:5748
        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 = 11
        channel = <optimized out>
        nfds = <optimized out>
        Available = {fds_bits = {32808, 0 <repeats 15 times>}}
        Writeok = {fds_bits = {0 <repeats 16 times>}}
        check_write = true
        check_delay = <optimized out>
        no_avail = false
        xerrno = 2
        proc = <optimized out>
        timeout = {tv_sec = 0, tv_nsec = 124947039}
        end_time = <optimized out>
        timer_delay = <optimized out>
        got_output_end_time = {tv_sec = 1750195811, tv_nsec = 219652299}
        wait = TIMEOUT
        got_some_output = -1
        prev_wait_proc_nbytes_read = 0
        retry_for_async = <optimized out>
        now = <optimized out>
#16 0x000000000043159d in sit_for (timeout=timeout@entry=0x96, reading=reading@entry=true, display_option=display_option@entry=1) at lisp.h:1192
        sec = 37
        nsec = 0
        do_display = true
        curbuf_eq_winbuf = true
        nbytes = <optimized out>
#17 0x0000000000547f46 in read_char (commandflag=1, map=0x31e9ec83, prev_event=0x0, used_mouse_menu=0x7ffc6645bcab, end_time=0x0) at lisp.h:1226
        tem0 = <optimized out>
        timeout = 37
        delay_level = <optimized out>
        buffer_size = <optimized out>
        c = 0x0
        local_getcjmp = {{__jmpbuf = {13838880, 2237550689305543785, 0, 817841440, 837414019, 140722024332816, -2236691474347539351, 2237551069047604329}, __mask_was_saved = 0, __saved_mask = {__val = {0, 836738805, 1, 6, 48096, 1, 6494148, 2, 6467199, 837428755, 1, 836738805, 48096, 53913, 53913, 836738800}}}}
        save_jump = {{__jmpbuf = {0, 0, 0, 0, 0, 0, 0, 0}, __mask_was_saved = 0, __saved_mask = {__val = {0 <repeats 16 times>}}}}
        tem = <optimized out>
        save = <optimized out>
        previous_echo_area_message = 0x0
        also_record = 0x0
        reread = false
        recorded = false
        polling_stopped_here = false
        orig_kboard = 0x30bf4520
#18 0x0000000000548b34 in read_key_sequence (keybuf=0x7ffc6645be10, prompt=0x0, dont_downcase_last=<optimized out>, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=<optimized out>, disable_text_conversion_p=false) at keyboard.c:10743
        interrupted_kboard = 0x30bf4520
        interrupted_frame = 0x30bcb3e0
        key = <optimized out>
        used_mouse_menu = false
        echo_local_start = 0
        last_real_key_start = 0
        keys_local_start = 0
        new_binding = <optimized out>
        t = 0
        echo_start = 0
        keys_start = 0
        current_binding = 0x31e9ec83
        first_unbound = 31
        mock_input = 0
        used_mouse_menu_history = {false <repeats 30 times>}
        fkey = {parent = 0x7fbdac6f98a3, map = 0x7fbdac6f98a3, start = 0, end = 0}
        keytran = {parent = 0x7fbd9749a683, map = 0x7fbd9749a683, start = 0, end = 0}
        indec = {parent = 0x7fbdac6f9893, map = 0x7fbdac6f9893, start = 0, end = 0}
        shift_translated = false
        delayed_switch_frame = 0x0
        original_uppercase = 0x539f22 <safe_run_hook_funcall+146>
        original_uppercase_position = -1
        disabled_conversion = <optimized out>
        starting_buffer = <optimized out>
        fake_prefixed_keys = 0x0
        first_event = 0x0
        second_event = <optimized out>
#19 0x000000000054a394 in command_loop_1 () at lisp.h:1192
        cmd = <optimized out>
        keybuf = {0x36, 0x18a, 0x7fbd973a343c, 0x60, 0x60, 0x0, 0x0, 0x111c0, 0x400000003f000000, 0x5be4f4 <unbind_to+516>, 0x0, 0x31ee8a03, 0xb, 0x111c0, 0x30, 0x30c8b715, 0x7fbd95e7fbb8, 0x60, 0x31ee8a03, 0x7ffc6645bed0, 0x0, 0x0, 0x7ffc6645c078, 0x53f0c6 <cmd_error+358>, 0xffffffffffffff00, 0x7ffc6645c044, 0xb, 0xb310, 0x0, 0x7fbd96f922a5}
        i = <optimized out>
        last_pt = <optimized out>
        prev_modiff = 1582
        prev_buffer = 0x32452810
#20 0x00000000005bd222 in internal_condition_case (bfun=bfun@entry=0x54a1d0 <command_loop_1>, handlers=handlers@entry=0x90, hfun=hfun@entry=0x53ef60 <cmd_error>) at eval.c:1613
        val = <optimized out>
        c = 0x30c7a5f0
#21 0x0000000000537c4a in command_loop_2 (handlers=handlers@entry=0x90) at keyboard.c:1168
        val = <optimized out>
#22 0x00000000005bd151 in internal_catch (tag=tag@entry=0x122d0, func=func@entry=0x537c30 <command_loop_2>, arg=arg@entry=0x90) at eval.c:1292
        val = <optimized out>
        c = 0x30c7a4b0
#23 0x0000000000537bef in command_loop () at lisp.h:1192
#24 0x000000000053eb16 in recursive_edit_1 () at keyboard.c:754
        val = <optimized out>
#25 0x000000000053eea4 in Frecursive_edit () at keyboard.c:837
        buffer = <optimized out>
#26 0x0000000000426797 in main (argc=<optimized out>, argv=<optimized out>) at emacs.c:2646
        stack_bottom_variable = 0x6169dcdcca4cd000
        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>