Subject: bug#40317: 27.0.90; Reverting a buffer that visits C file signals an error

From: Alan Mackenzie <[email-masked]>
Date: Fri, 18 Sep 2020 20:13:35 +0000

Hello, Jeff.

Thanks for contributing towards this bug.

On Thu, Sep 17, 2020 at 20:21:47 -0500, Jeff Norden wrote:
> I came across this by searching for args-out-of-range bugs.  I recently found
> a bug in forward-comment (which I'll post separately) that was causing
> out-of-range errors for me, and I wondered if forward-comment might be
> relevant to other issues.  It isn't in this case, but I think I did find the
> source of the problem.

> The function c-after-change (in cc-mode.el) was changed between 26.3 and 27.1,
> to handle more cases where the before and/or after change functions get called
> multiple times.  The function now begins (line numbers are from the current
> master version) with:

> 1993   ;; Note: c-just-done-before-change is nil, t, or 'whole-buffer.
> 1994   (unless (c-called-from-text-property-change-p)
> 1995     (save-restriction
> 1996       (widen)
> 1997       (unless c-just-done-before-change
> 1998         (c-before-change (point-min) (point-max)))
> 1999       (unless (eq c-just-done-before-change t)
> 2000         (setq beg (point-min)
> 2001               end (point-max)
> 2002               old-len (- end beg)
> 2003               c-new-BEG (point-min)
> 2004               c-new-END (point-max)))
> 2005       (setq c-just-done-before-change nil)))
> 2006 
> 2007   ;; (c-new-BEG c-new-END) will be the region to fontify.  It may become
> 2008   ;; larger than (beg end).
> 2009   (setq c-new-END (- (+ c-new-END (- end beg)) old-len))

> It looks like it is now possible for the last line above, which increments
> c-new-END, to run even if c-new-END has been set to the after-change value
> of point-max.  That will make c-new-END point past the end of the buffer.

[ .... ]

> Unfortunately, I can't figure out how to trigger this bug myself.  If you want
> to be 100% sure about it, you might try adding

I've spent quite a long time looking at this, trying various means to
trigger the error (via `insert-file-contents' and `revert-buffer').

Then it suddenly dawned on me that the (setq c-new-END (.....)) is OK.
If the body of the the last `unless' has been run, (- end beg) and
old-len are equal to each other, and to the buffer length.  So c-new-END
doesn't get changed in this case.

Of course, it's hopelessly confusing coding.  It seems to have confused
you, and it certainly confused me, even though I wrote it myself only a
short while ago.

If that code is to remain as it is, it definitely needs commenting.
There seems to be an aesthetic benefit in keeping the (setq c-new-BEG
...) separate from the ~13 line section which deals with the
out-of-sequence calling of before-change-functions and
after-change-functions.  But I'll sleep on that thought.

[ .... ]

> Hope this helps,
> -Jeff

Yes, it has helped, thanks.

-- 
Alan Mackenzie (Nuremberg, Germany).