bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#39977: 28.0.50; Unhelpful stack trace


From: martin rudalics
Subject: bug#39977: 28.0.50; Unhelpful stack trace
Date: Sat, 28 Mar 2020 19:38:24 +0100

>>   >> (and (frame-live-p (selected-frame))
>>   >>        (window-live-p (selected-window))
>>   >>        (eq (frame-selected-window (selected-frame))
>>   >>      (selected-window)))
>>   >
>>   > I agree.  But note that selected-frame could switch frames internally,
>>   > if the last selected frame is dead; as long as selected-frame also
>>   > adjusts the selected window, the above will still hold.
>>
>> Do you mean 'select-frame' instead of 'selected-frame'?
>
> No, I meant selected-frame.

So you meant a 'selected-frame' based on the SELECTED_FRAME I proposed.
The problem is that that macro won't protect the invariant if it was
broken before, for example, by setting the selected window to a dead
window as in Madhu's scenario.

> Perhaps we should make unwind_format_mode_line less fragile, then.

The problematic step happens already at the time we set it up.  In a
nutshell, Madhu's scenario goes as follows: In display_mode_lines we do

  Lisp_Object old_selected_window = selected_window;
  Lisp_Object old_selected_frame = selected_frame;
...
      display_mode_line (w, CURRENT_MODE_LINE_FACE_ID_3 (sel_w, sel_w, w),
                         NILP (window_mode_line_format)
                         ? BVAR (current_buffer, mode_line_format)
                         : window_mode_line_format);
...
  XFRAME (new_frame)->selected_window = old_frame_selected_window;
  selected_frame = old_selected_frame;
  selected_window = old_selected_window;

where display_mode_line deletes both, old_selected_frame and
old_selected_window.  So we end up with selected_frame and
selected_window both referencing dead objects.  The subsequent call of
gui_consider_frame_title now does

      record_unwind_protect (unwind_format_mode_line,
                             format_mode_line_unwind_data
                               (f, current_buffer, selected_window, false));

where selected_window is already a dead window.  Since in
unwind_format_mode_line old_window is non-nil, it will call

      Fselect_window (old_window, Qt);

which first chokes on

   CHECK_LIVE_WINDOW (window);

which is the error reported when emacs does not crash and finally on

  sf = SELECTED_FRAME ();

which crashes emacs due to the fact that selected_frame is dead.  In
either case, making the unwind_format_mode_line less fragile won't avoid
any crash, it might just postpone it.

>> And I have no idea yet why we need an extra unwind for restoring
>> selected_frame and selected_window.  Shouldn't these go hand in hand
>> with what unwind_format_mode_line does?  Does the one even know
>> about the other?
>
> I don't think I understand what extra unwind are you talking about
> here.  Can you provide a more specific pointer to the relevant code?

I meant the fact that we already do unwind_format_mode_line when
formatting the mode line and that function could restore the selected
window in a safe way.  I'm far from proposing to use that approach when
drawing the mode lines, though.

Attached find a patch which should solve the more grave problems caused
by a function deleting the previously selected frame or window.  It
intentionally does not change SELECTED_FRAME.  Any abort there should be
reserved to obscure bugs we have not been able to trace yet.  Please
read it with your usual care, it took me some time to convince myself
that it selects its frame in a reasonable way.

On master, I would then like to use restore_selected_window also for
gui_consider_frame_title.  The overhead caused by that is a great
annoyance (especially when debugging frame switching code) and we could
then hopefully get rid of the old_window stuff and the Bug#32777 fix as
well.

What any patch I provide here cannot do is to fix problems when the mode
line code deletes the selected window right away.  Code like


(defvar window (split-window))

(defvar foo
  '(:eval
    (if (or (not (window-live-p window))
            (eq window (frame-first-window)))
        (setq window (split-window))
      (delete-window window))))

(setq-default mode-line-format foo)


will continue to segfault unless you can cure that.  I tried to fix it
in the spirit of

                if (!FRAME_LIVE_P (it->f))
                  signal_error (":eval deleted the frame being displayed", elt);

but that just caused emacs to hang.

martin

Attachment: restore_selected_window.diff
Description: Text Data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]