From f357a549ac7434ce5d1011c5d8fa09997fd8a13d Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 1 Jun 2026 15:03:45 +0300 Subject: [PATCH] Prevent segfaults due to frame resizing at the wrong time * src/dispextern.h: * src/xdisp.c (dont_resize_frames): New variable. (unwind_format_mode_line): Decrement 'dont_resize_frames'. (gui_consider_frame_title, display_mode_line, Fformat_mode_line): Increment 'dont_resize_frames'. * src/dispnew.c (do_pending_window_change): Don't resize frames if 'dont_resize_frames' is non-zero. (Bug#81121) (cherry picked from commit 94eb6389d403eb1b71a81ecdc3b8416cf5f850d6) --- src/dispextern.h | 1 + src/dispnew.c | 2 +- src/xdisp.c | 21 +++++++++++++++++++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index d08bd7ee7a9..b75bdff7bc6 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3591,6 +3591,7 @@ int frame_mode_line_height (struct frame *); extern bool redisplaying_p; extern unsigned int redisplay_counter; extern bool display_working_on_window_p; +extern int dont_resize_frames; extern void unwind_display_working_on_window (void); extern bool help_echo_showing_p; extern Lisp_Object help_echo_string, help_echo_window; diff --git a/src/dispnew.c b/src/dispnew.c index 284a0eb175f..155075570a7 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -6664,7 +6664,7 @@ deliver_window_change_signal (int sig) void do_pending_window_change (bool safe) { - if (redisplaying_p && !safe) + if ((redisplaying_p || dont_resize_frames) && !safe) return; while (delayed_size_change) diff --git a/src/xdisp.c b/src/xdisp.c index c1d6fedb553..b3c6fb8a486 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -1077,6 +1077,14 @@ bool redisplaying_p; the callers. */ bool display_working_on_window_p; +/* Non-zero when we do not allow resizing frames. For example, + display_mode_line and other functions produce glyphs for the mode + line, in particular when called from non-redisplay code (so + redisplaying_p is false). We inhibit resizing of the frames during + that time, because that could change glyph_row pointers in the glyph + matrix behind the back of teh code which manipulates these pointers. */ +int dont_resize_frames; + /* If a string, XTread_socket generates an event to display that string. (The display is done in read_char.) */ @@ -14015,6 +14023,9 @@ unwind_format_mode_line (Lisp_Object vector) } Vmode_line_unwind_vector = vector; + + if (dont_resize_frames > 0) + dont_resize_frames--; } @@ -14151,6 +14162,7 @@ gui_consider_frame_title (Lisp_Object frame) title_start = MODE_LINE_NOPROP_LEN (0); init_iterator (&it, XWINDOW (f->selected_window), -1, -1, NULL, DEFAULT_FACE_ID); + dont_resize_frames++; display_mode_element (&it, 0, -1, -1, fmt, Qnil, false); len = MODE_LINE_NOPROP_LEN (title_start); title = mode_line_noprop_buf + title_start; @@ -28138,6 +28150,10 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) format_mode_line_unwind_data (NULL, NULL, Qnil, false)); + /* We cannot allow frame-resizing as long as the code below runs, + because that could invalidate the it.glyph_row->glyphs pointers. */ + dont_resize_frames++; + /* Temporarily make frame's keyboard the current kboard so that kboard-local variables in the mode_line_format will get the right values. */ @@ -28253,8 +28269,6 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) } pop_kboard (); - unbind_to (count, Qnil); - /* Fill up with spaces. */ display_string (" ", Qnil, Qnil, 0, 0, &it, 10000, -1, -1, 0); @@ -28284,6 +28298,8 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format) - (it.current_x - it.last_visible_x))); } + unbind_to (count, Qnil); + return it.glyph_row->height; } @@ -29026,6 +29042,7 @@ are the selected window and the WINDOW's buffer). */) set_buffer_internal_1 (XBUFFER (buffer)); init_iterator (&it, w, -1, -1, NULL, face_id); + dont_resize_frames++; /* Make sure `base_line_number` is fresh in case we encounter a `%l`. */ if (current_buffer == XBUFFER ((w)->contents)