Package: emacs;
Reported by: Daniel Clemente <n142857 <at> gmail.com>
Date: Sun, 6 Jul 2025 13:55:02 UTC
Severity: normal
Found in version 31.0.50
To reply to this bug, email your comments to 78966 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
bug-gnu-emacs <at> gnu.org
:bug#78966
; Package emacs
.
(Sun, 06 Jul 2025 13:55:02 GMT) Full text and rfc822 format available.Daniel Clemente <n142857 <at> gmail.com>
:bug-gnu-emacs <at> gnu.org
.
(Sun, 06 Jul 2025 13:55:03 GMT) Full text and rfc822 format available.Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Daniel Clemente <n142857 <at> gmail.com> To: bug-gnu-emacs <at> gnu.org Subject: 31.0.50; Crash when pressing a key while a new frame is opening in a TTY Date: Sun, 6 Jul 2025 13:53:44 +0000
Reproduction ============ 1. Open emacs --fg-daemon -Q (I haven't reproduced it without the daemon) 2. In a terminal (I have reproduced it in X terminals: both urxvt and xterm), prepare to open: emacsclient -nw 3. Press the enter key to run the command, but keep holding it while emacsclient opens. If you can launch emacsclient in any other way, holding another key instead, like „space“ or „a“ or an arrow key, will also reproduce the crash 4. In many cases it crashes. If not, exit (C-x C-c) and repeat step 3 a few times (up to ~20) To simplify testing, use this loop and, while it runs, hold a key („a“) down for a few seconds (usually <10, maximum ~60); it always triggers the crash: while :; do emacsclient -nw -e '(delete-frame)'; sleep 0.1 && done In user terms, this means that if I launch emacsclient (via a key in my window manager) and start typing very fast, very often it crashes. The workaround of course is to wait until the frame is fully opened. I compiled emacs without X support. Apart from that, my setup is standard (1 keyboard) and this happens under -Q, with no customization. And only 1 simultaneous frame is needed. Origin ====== I bisected the commits and found that the crash started happening only after this change, on 2025-02-10: 4d1ceac9f9332f74ac2ab300eb2a629ea742b1dc Author: Martin Rudalics <rudalics <at> gmx.at> AuthorDate: Mon Feb 10 10:36:38 2025 +0100 Parent: 302274b1862 * lisp/treesit.el: Fix treesit-outline. Fix handling of visibility on tty frames (Bug#76031) It doesn't happen in the previous commit, 302274b1862. Crash in gdb ============ The crash at kbd_buffer_get_event (the line numbers are from a recent codebase from this week): Breakpoint 1, terminate_due_to_signal (sig=6, backtrace_limit=2147483647) at emacs.c:443 443 signal (sig, SIG_DFL); (gdb) bt #0 terminate_due_to_signal (sig=6, backtrace_limit=2147483647) at emacs.c:443 #1 0x0000555555748913 in die (msg=0x555555875eec "FRAMEP (frame)", file=0x555555875d4a "keyboard.c", line=4296) at alloc.c:7355 #2 0x00005555556a7d93 in kbd_buffer_get_event (kbp=0x7fffffffd048, used_mouse_menu=0x7fffffffd6cf, end_time=0x0) at keyboard.c:4296 #3 0x00005555556a347e in read_event_from_main_queue (end_time=0x0, local_getcjmp=0x7fffffffd490, used_mouse_menu=0x7fffffffd6cf) at keyboard.c:2325 #4 0x00005555556a3788 in read_decoded_event_from_main_queue (end_time=0x0, local_getcjmp=0x7fffffffd490, prev_event=XIL(0), used_mouse_menu=0x7fffffffd6cf) at keyboard.c:2389 #5 0x00005555556a50d9 in read_char (commandflag=1, map=XIL(0x7ffff089ed43), prev_event=XIL(0), used_mouse_menu=0x7fffffffd6cf, end_time=0x0) at keyboard.c:3020 #6 0x00005555556b6d55 in read_key_sequence (keybuf=0x7fffffffd8e0, prompt=XIL(0), dont_downcase_last=false, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=false, disable_text_conversion_p=false) at keyboard.c:10867 #7 0x00005555556a08b6 in command_loop_1 () at keyboard.c:1424 #8 0x0000555555781bbe in internal_condition_case (bfun=0x5555556a0481 <command_loop_1>, handlers=XIL(0x90), hfun=0x55555569f8d8 <cmd_error>) at eval.c:1684 #9 0x00005555556a0029 in command_loop_2 (handlers=XIL(0x90)) at keyboard.c:1163 #10 0x0000555555781041 in internal_catch (tag=XIL(0xfdb0), func=0x55555569fff9 <command_loop_2>, arg=XIL(0x90)) at eval.c:1364 #11 0x000055555569ffb5 in command_loop () at keyboard.c:1141 #12 0x000055555569f346 in recursive_edit_1 () at keyboard.c:749 #13 0x000055555569f57e in Frecursive_edit () at keyboard.c:832 #14 0x000055555569a962 in main (argc=3, argv=0x7fffffffdef8) at emacs.c:2582 (gdb) frame 2 #2 0x00005555556a7d93 in kbd_buffer_get_event (kbp=0x7fffffffd048, used_mouse_menu=0x7fffffffd6cf, end_time=0x0) at keyboard.c:4296 4296 focus = FRAME_FOCUS_FRAME (XFRAME (frame)); (gdb) list 4291 if (CONSP (frame)) 4292 frame = XCAR (frame); 4293 else if (WINDOWP (frame)) 4294 frame = WINDOW_FRAME (XWINDOW (frame)); 4295 4296 focus = FRAME_FOCUS_FRAME (XFRAME (frame)); 4297 if (! NILP (focus)) 4298 frame = focus; 4299 4300 if (!EQ (frame, internal_last_event_frame) (gdb) p frame $1 = XIL(0) (gdb) (gdb) p event $5 = (union buffered_input_event *) 0x555555941e60 <kbd_buffer+1152> (gdb) p *event $6 = { kind = ASCII_KEYSTROKE_EVENT, ie = { kind = ASCII_KEYSTROKE_EVENT, part = scroll_bar_nowhere, code = 13, modifiers = 0, x = XIL(0), y = XIL(0), timestamp = 0, frame_or_window = XIL(0), arg = XIL(0), device = XIL(0x30) } } (gdb) event.frame_or_window is null. Ideas ===== What follows now is just brainstorming (but with little knowledge of Emacs internals). First I thought that kbd_buffer_get_event could just skip events with a null frame_or_window. Or maybe: some other code shouldn't create „normal keystroke“ events with a null frame_or_window. But skipping events shouldn't mean losing keystrokes. If I open Emacs and type abcd very fast while it's opening, I expect abcd to appear later inside Emacs, not to be lost. Maybe it's better: if frame_or_window is null, then don't process the event yet, but process it later (when the frame has been initialized). read_event_from_main_queue says: /* Read from the main queue, and if that gives us something we can't use yet, we put it on the appropriate side queue and try again. */ So maybe it should do this when a frame hasn't been initialized yet. I see CHECK_LIVE_FRAME (frame_or_window) in other parts of the code, that could help. Or it may be a bug somewhere else, or something missing from bug#76031. Another related bug report is: bug#75056: 31.0.50; tty-child-frames with server / multiple clients possible hangs More debug info =============== In case it might be useful: (gdb) frame 3 #3 0x00005555556a347e in read_event_from_main_queue (end_time=0x0, local_getcjmp=0x7fffffffd490, used_mouse_menu=0x7fffffffd6cf) at keyboard.c:2325 2325 c = kbd_buffer_get_event (&kb, used_mouse_menu, end_time); (gdb) p kb $12 = (KBOARD *) 0x555555ab5af0 (gdb) p *kb $13 = { next_kboard = 0x555555a379c0, Voverriding_terminal_local_map_ = XIL(0), Vlast_command_ = XIL(0), Vreal_last_command_ = XIL(0), Vkeyboard_translate_table_ = XIL(0x555555b72a5d), Vlast_repeatable_command_ = XIL(0), Vprefix_arg_ = XIL(0), Vlast_prefix_arg_ = XIL(0), kbd_queue_ = XIL(0), defining_kbd_macro_ = XIL(0), kbd_macro_buffer = 0x0, kbd_macro_ptr = 0x707974040200090e, kbd_macro_end = 0x6e75020200040d65, kbd_macro_bufsize = 0, Vlast_kbd_macro_ = XIL(0), Vsystem_key_alist_ = XIL(0), system_key_syms_ = XIL(0), Vwindow_system_ = XIL(0), Vlocal_function_key_map_ = XIL(0x7ffff08460f3), Vinput_decode_map_ = XIL(0x7ffff08460e3), Vdefault_minibuffer_frame_ = XIL(0), reference_count = 1, echo_string_ = XIL(0), kbd_queue_has_data = false, immediate_echo = false, echo_prompt_ = XIL(0) } (gdb) p end_time $14 = (struct timespec *) 0x0 (gdb) Emacs data ========== In GNU Emacs 31.0.50 (build 9, x86_64-pc-linux-gnu) of 2025-07-05 built on sonn Repository revision: 763c3cd081a833940961373a73705640b1808636 Repository branch: master System Description: Devuan GNU/Linux 5 (daedalus) Configured using: 'configure --prefix=/opt/dc/emacs-dev/ --with-tiff=no --without-tiff --without-libsystemd --without-dbus --with-mailutils --without-modules --with-native-compilation --with-x-toolkit=no --without-imagemagick --without-xft --without-harfbuzz --without-freetype --without-libotf --without-xwidgets --without-xpm --without-jpeg --without-gif --without-png --without-webp --without-rsvg --without-cairo --without-x --without-sound --enable-checking=yes,glyphs --enable-profiling 'CFLAGS=-g3 -O0 '' Configured features: GMP GNUTLS LCMS2 LIBSELINUX LIBXML2 NATIVE_COMP NOTIFY INOTIFY PDUMPER SECCOMP SQLITE3 THREADS XIM ZLIB Important settings: value of $LANG: en_US.UTF-8 value of $XMODIFIERS: @im=SCIM locale-coding-system: utf-8-unix Major mode: Lisp Interaction Minor modes in effect: server-mode: t tooltip-mode: t global-eldoc-mode: t eldoc-mode: t show-paren-mode: t electric-indent-mode: t menu-bar-mode: t file-name-shadow-mode: t global-font-lock-mode: t font-lock-mode: t blink-cursor-mode: t minibuffer-regexp-mode: t line-number-mode: t indent-tabs-mode: t transient-mark-mode: t auto-composition-mode: t auto-encryption-mode: t auto-compression-mode: t Load-path shadows: None found. Features: (shadow sort mail-extr emacsbug lisp-mnt message mailcap yank-media puny dired dnd dired-loaddefs rfc822 mml mml-sec password-cache epa derived epg rfc6068 epg-config gnus-util time-date mm-decode mm-bodies mm-encode mail-parse rfc2231 mailabbrev gmm-utils mailheader sendmail rfc2047 rfc2045 ietf-drums mm-util mail-prsvr mail-utils term/rxvt term/xterm xterm byte-opt gv compile text-property-search comint subr-x ansi-osc ansi-color ring tool-bar comp-run bytecomp byte-compile comp-common regexp-opt rx server warnings icons cl-loaddefs cl-lib rmc iso-transl tooltip cconv eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type elisp-mode tabulated-list replace newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow isearch easymenu timer select mouse jit-lock font-lock syntax font-core term/tty-colors frame minibuffer nadvice seq simple cl-generic indonesian philippine cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european ethiopic indian cyrillic chinese composite emoji-zwj charscript charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp files window text-properties overlay sha1 md5 base64 format env code-pages mule custom widget keymap hashtable-print-readable backquote threads inotify lcms2 multi-tty make-network-process tty-child-frames native-compile emacs) Memory information: ((conses 16 65067 12567) (symbols 48 7221 1) (strings 32 18992 5374) (string-bytes 1 568316) (vectors 16 9656) (vector-slots 8 92267 12318) (floats 8 31 11521) (intervals 56 265 0) (buffers 984 13))
bug-gnu-emacs <at> gnu.org
:bug#78966
; Package emacs
.
(Sun, 06 Jul 2025 14:35:05 GMT) Full text and rfc822 format available.Message #8 received at 78966 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Daniel Clemente <n142857 <at> gmail.com>, martin rudalics <rudalics <at> gmx.at> Cc: 78966 <at> debbugs.gnu.org Subject: Re: bug#78966: 31.0.50; Crash when pressing a key while a new frame is opening in a TTY Date: Sun, 06 Jul 2025 17:34:25 +0300
> From: Daniel Clemente <n142857 <at> gmail.com> > Date: Sun, 6 Jul 2025 13:53:44 +0000 > > Reproduction > ============ > > 1. Open emacs --fg-daemon -Q (I haven't reproduced it without the daemon) > 2. In a terminal (I have reproduced it in X terminals: both urxvt and > xterm), prepare to open: emacsclient -nw > 3. Press the enter key to run the command, but keep holding it while > emacsclient opens. If you can launch emacsclient in any other way, > holding another key instead, like „space“ or „a“ or an arrow key, will > also reproduce the crash > 4. In many cases it crashes. If not, exit (C-x C-c) and repeat step 3 > a few times (up to ~20) > > To simplify testing, use this loop and, while it runs, hold a key > („a“) down for a few seconds (usually <10, maximum ~60); it always > triggers the crash: > while :; do emacsclient -nw -e '(delete-frame)'; sleep 0.1 && done > > In user terms, this means that if I launch emacsclient (via a key in > my window manager) and start typing very fast, very often it crashes. > The workaround of course is to wait until the frame is fully opened. > > I compiled emacs without X support. Apart from that, my setup is > standard (1 keyboard) and this happens under -Q, with no > customization. And only 1 simultaneous frame is needed. > > > Origin > ====== > > I bisected the commits and found that the crash started happening only > after this change, on 2025-02-10: > > 4d1ceac9f9332f74ac2ab300eb2a629ea742b1dc > Author: Martin Rudalics <rudalics <at> gmx.at> > AuthorDate: Mon Feb 10 10:36:38 2025 +0100 > Parent: 302274b1862 * lisp/treesit.el: Fix treesit-outline. > Fix handling of visibility on tty frames (Bug#76031) > > It doesn't happen in the previous commit, 302274b1862. > > Crash in gdb > ============ > > The crash at kbd_buffer_get_event (the line numbers are from a recent > codebase from this week): > > > Breakpoint 1, terminate_due_to_signal (sig=6, > backtrace_limit=2147483647) at emacs.c:443 > 443 signal (sig, SIG_DFL); > (gdb) bt > #0 terminate_due_to_signal (sig=6, backtrace_limit=2147483647) at emacs.c:443 > #1 0x0000555555748913 in die (msg=0x555555875eec "FRAMEP (frame)", > file=0x555555875d4a "keyboard.c", line=4296) at alloc.c:7355 > #2 0x00005555556a7d93 in kbd_buffer_get_event (kbp=0x7fffffffd048, > used_mouse_menu=0x7fffffffd6cf, end_time=0x0) at keyboard.c:4296 I guess this fragment from tty_read_avail_input is suspect: /* Set the frame corresponding to the active tty. Note that the value of selected_frame is not reliable here, redisplay tends to temporarily change it. However, if the selected frame is a child frame, don't do that since it will cause switch frame events to switch to the root frame instead. */ if (FRAME_PARENT_FRAME (XFRAME (selected_frame)) && (root_frame (XFRAME (selected_frame)) == XFRAME (tty->top_frame))) buf.frame_or_window = selected_frame; else buf.frame_or_window = tty->top_frame; It somehow assigns nil to the event's frame_or_window field. P.S. I couldn't reproduce the problem on my system, no matter how many times I tried.
bug-gnu-emacs <at> gnu.org
:bug#78966
; Package emacs
.
(Sun, 06 Jul 2025 16:56:03 GMT) Full text and rfc822 format available.Message #11 received at 78966 <at> debbugs.gnu.org (full text, mbox):
From: martin rudalics <rudalics <at> gmx.at> To: Eli Zaretskii <eliz <at> gnu.org>, Daniel Clemente <n142857 <at> gmail.com> Cc: Gerd Möllmann <gerd.moellmann <at> gmail.com>, 78966 <at> debbugs.gnu.org Subject: Re: bug#78966: 31.0.50; Crash when pressing a key while a new frame is opening in a TTY Date: Sun, 6 Jul 2025 18:55:46 +0200
[Message part 1 (text/plain, inline)]
> I guess this fragment from tty_read_avail_input is suspect: > > /* Set the frame corresponding to the active tty. Note that the > value of selected_frame is not reliable here, redisplay tends > to temporarily change it. However, if the selected frame is a > child frame, don't do that since it will cause switch frame > events to switch to the root frame instead. */ > if (FRAME_PARENT_FRAME (XFRAME (selected_frame)) > && (root_frame (XFRAME (selected_frame)) > == XFRAME (tty->top_frame))) > buf.frame_or_window = selected_frame; > else > buf.frame_or_window = tty->top_frame; > > It somehow assigns nil to the event's frame_or_window field. Right. tty->top_frame is Qnil here. I have not the slightest idea _when_ we should initialize tty->top_frame whenever we create a frame on a tty. Maybe Gerd has. Meanwhile I can offer the attached patch. Thanks Daniel for the detailed report, martin
[keyboard.c.diff (text/x-patch, attachment)]
bug-gnu-emacs <at> gnu.org
:bug#78966
; Package emacs
.
(Sun, 06 Jul 2025 18:34:03 GMT) Full text and rfc822 format available.Message #14 received at 78966 <at> debbugs.gnu.org (full text, mbox):
From: Gerd Möllmann <gerd.moellmann <at> gmail.com> To: martin rudalics <rudalics <at> gmx.at> Cc: Daniel Clemente <n142857 <at> gmail.com>, Eli Zaretskii <eliz <at> gnu.org>, 78966 <at> debbugs.gnu.org Subject: Re: bug#78966: 31.0.50; Crash when pressing a key while a new frame is opening in a TTY Date: Sun, 06 Jul 2025 20:33:16 +0200
martin rudalics <rudalics <at> gmx.at> writes: >> I guess this fragment from tty_read_avail_input is suspect: >> >> /* Set the frame corresponding to the active tty. Note that the >> value of selected_frame is not reliable here, redisplay tends >> to temporarily change it. However, if the selected frame is a >> child frame, don't do that since it will cause switch frame >> events to switch to the root frame instead. */ >> if (FRAME_PARENT_FRAME (XFRAME (selected_frame)) >> && (root_frame (XFRAME (selected_frame)) >> == XFRAME (tty->top_frame))) >> buf.frame_or_window = selected_frame; >> else >> buf.frame_or_window = tty->top_frame; >> >> It somehow assigns nil to the event's frame_or_window field. > > Right. tty->top_frame is Qnil here. I have not the slightest idea > _when_ we should initialize tty->top_frame whenever we create a frame on > a tty. Maybe Gerd has. Meanwhile I can offer the attached patch. I haven't a good idea either I'm afraid. I was relying on do_switch_frame being called and setting top_frame. I can only guess this is torpedoed by input being available right away before do_switch_frame had a chance to run. That's only a guess though. Maybe one could set top_frame in make_terminal_frame when a new root frame is created? That at least doesn't sound completely unreasonable because in that case, one could argue the new root frame is the to-be top_frame. Another idea would be to wait with handling events in command_loop_1 until the frames/the terminal are fully functional. But we don't have anything resembling that AFAIR. And command_loop_1 and what's called from there is already complicated enough. I'd say your solution is a good one, and economic.
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.