Subject: bug#78444: 30.1; Crash in GC (vector_marked_p)

From: Pip Cet <[email-masked]>
Date: Sun, 15 Jun 2025 17:49:42 +0000

"George P" <[email-masked]> writes:

> Yes, that is precisely what it says....
>
> (gdb) p displayed_buffer
> $1 = (struct buffer *) 0xfffffffffffffffb

That's XBUFFER (Qnil), possibly set by this code in redisplay_internal:

  else if (FRAME_REDISPLAY_P (sf) && !FRAME_OBSCURED_P (sf))
    {
      sf->inhibit_clear_image_cache = true;
      displayed_buffer = XBUFFER (XWINDOW (selected_window)->contents);
      /* Use list_of_error, not Qerror, so that
	 we catch only errors and don't run the debugger.  */
      internal_condition_case_1 (redisplay_window_1, selected_window,
				 list_of_error,
				 redisplay_window_error);

However, I believe that's only the surface of the bug: the selected
window's contents should never be nil, right?  According to this comment
in window.h, that would mean it's a pseudo window, but another comment
says the selected window is always a leaf window:

    /* For a leaf window or a tooltip window this is the buffer shown
       in the window; for a combination window this is the first of
       its child windows; for a pseudo window showing the menu bar or
       tool bar this is nil.  It is a buffer for a minibuffer window
       as well.  */
    Lisp_Object contents;

/* This is the window in which the terminal's cursor should be left when
   nothing is being done with it.  This must always be a leaf window, and its
   buffer is selected by the top level editing loop at the end of each command.

   This value is always the same as FRAME_SELECTED_WINDOW (selected_frame).  */

So this looks like an inconsistent state reached by the redisplay
machinery.  We'd have to check whether it's the code above or actually
this code:

      if (update_miniwindow_p)
	{
	  Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf);

	  displayed_buffer = XBUFFER (XWINDOW (mini_window)->contents);
	  internal_condition_case_1 (redisplay_window_1, mini_window,
				     list_of_error,
				     redisplay_window_error);
	}

While it would probably would have avoided the crash to check whether
XWINDOW (whichever)->contents is Qnil before setting displayed_buffer,
I don't think that's the right fix: violating that internal redisplay
assumption is a bad thing, and we need to figure out why it can happen
when windows are being deleted (possibly in delete-window-internal?)

Can you look up the line numbers against your source tree to see which
code segment was active when the error happened?

Thanks!
Pip