Subject: bug#27668: 26.0.50; Crash with display-line-numbers t

From: Eli Zaretskii <[email-masked]>
Date: Fri, 14 Jul 2017 18:14:44 +0300

> From: Robert Pluim <[email-masked]>
> Date: Fri, 14 Jul 2017 16:47:56 +0200
> 
> > When the assertion in maybe_produce_line_number is hit, what are the
> > values of it->vpos and it->glyph_row->y?  Are they always the same
> > values?  If they are, maybe we could put a watchpoint on the
> > corresponding glyph row and see who changes it.
> 
> They're both always 0.
> 
> 21012	  eassert (it->glyph_row == NULL || it->glyph_row->used[TEXT_AREA] == 0);
> (gdb) p it->vpos
> $5 = 0
> (gdb) p it->glyph_row->y
> $6 = 0

That's the first row of desired_matrix.

> > The problem seems to be that display_line starts producing glyphs in a
> > glyph row which wasn't cleared, i.e. its used[1] counter is non-zero.
> > The call to prepare_desired_row at the beginning of display_line is
> > supposed to do that, but only if the row->enabled_p flag is reset.
> > This flag should be reset for all the glyph rows of the window's
> > desired_matrix, because redisplay calls clear_glyph_matrix for
> > w->desired_matrix, directly and indirectly, in many places.  Somehow
> > in your case either those calls to clear_glyph_matrix are bypassed or
> > some code sets the enabled_p flag at some point and doesn't reset it
> > before the call to try_window on line 16991 of xdisp.c.  I'm trying to
> > establish where does this happen and why.
> >
> > Just to make sure I'm on the right track: if you make the change
> > below, does the problem go away?
> >
> 
> Yes. Without the patch I ran my eww recipe three times, it crashed
> three times. With the patch, I ran it three times in 3 separate
> instances of emacs, no crash so far (and I tried a bunch of the magit
> related operations as well for good measure, and I'm using the
> resulting emacs to send this).

Great, thanks.  So here's the next step: we set a hardware watchpoint
on the enabled_p flag of that glyph row, and see who sets it.  You
will need to remove that line which fixed the problem, I guess.

Below please find the transcript of what I did to set up the snare:

 (gdb) break Fredraw_display
 (gdb) r -Q

Inside Emacs:

  ; Put the following in *scratch*
  (setq display-line-number t)
  C-x C-e 
  M-x eww RET https://revoked.badssl.com/ RET
  M-x redraw-display RET

Now GDB kicks in, so:

  3031      FOR_EACH_FRAME (tail, frame)
  (gdb) p selected_window
  $1 = XIL(0xa000000001b4e6f0)
  (gdb) p XWINDOW(selected_window)->contents
  $2 = XIL(0xa000000007047b30)
  (gdb) p XWINDOW(selected_window)
  $3 = (struct window *) 0x1b4e6f0 <dumped_data+3998768>
  (gdb) p XWINDOW(selected_window)->contents
  $4 = XIL(0xa000000007047b30)
  (gdb) xtype
  Lisp_Vectorlike
  PVEC_BUFFER
  (gdb) xbuffer
  $5 = (struct buffer *) 0x7047b30
  (unsigned char *) 0x6ffc1ec "*eww*"
  (gdb) p XWINDOW(selected_window)->desired_matrix
  $6 = (struct glyph_matrix *) 0x6850008
  (gdb) p XWINDOW(selected_window)->desired_matrix->rows
  $7 = (struct glyph_row *) 0xfae158
  (gdb) p XWINDOW(selected_window)->desired_matrix->rows->enabled_p
  $8 = false
  (gdb) watch -l $3->desired_matrix->rows->enabled_p
  Hardware watchpoint 4: -location $3->desired_matrix->rows->enabled_p
  (gdb) commands
  Type commands for breakpoint(s) 4, one per line.
  End with a line saying just "end".
  >bt
  >continue
  >end
  (gdb) c
  Continuing.

(Note that the $3 thing could be a different number in your case: it
depends on the number GDB gives to the output where it shows the
'struct window' of the selected-window.  The commands I typed after
that were just to make sure I'm in the right buffer and so the window
is indeed the one we are interested in.)

Back in Emacs, type 'q'.  This should produce several hits of the
watchpoint, and show the backtraces; post them here.

In my case, I see that prepare_desired_row sets the flag, then
update_window calls clear_glyph_matrix which resets the flag.  This is
the expected sequence: update_window is called after we've actually
redrawn the window to the glass, so it clears the glyph matrix in
preparation for the next redisplay.  In your case, I expect to see
at least one more hit, and the assertion violation.