Subject: Re: bug#7876: Crash: infinite recursion in next_element_from_buffer
From: Stefan Monnier <[email-masked]>
To: Eli Zaretskii <[email-masked]>
Cc: [email-masked]
Date: Mon, 24 Jan 2011 17:09:58 -0500
List-Id: <debbugs-submit.debbugs.gnu.org>

Thanks a lot, Eli, I think I've found the problem:

the stop_pos is stuck there, because it's the end of the buffer, but
end_charpos points further than ZV.

The reason for that is that grep.el's font-lock code doesn't just
add/remove text properties but also removes text.  In the old
compile.el, jit-lock is disabled so font-lock is run when the text is
inserted, but with my new compile.el, jit-lock can be (and is, by
default) enabled, so the end_charpos becomes invalid after running
jit-lock, and the redisplay code doesn't seem to pay attention to
this possibility.

I'm not very happy with grep.el's modifying the buffer like that from
font-lock-keywords, but neither is it OK for the redisplay to get stuck
in such an inf-loop.

I've installed the patch below in the emacs-23 branch, to account for
this particular case, although the jit-lock code could do nastier things
(e.g. add/remove text before the current position, thus rendering
IT_CHARPOS invalid).

        Stefan

=== modified file 'src/xdisp.c'
--- src/xdisp.c	2011-01-02 23:50:46 +0000
+++ src/xdisp.c	2011-01-24 22:02:26 +0000
@@ -3337,6 +3337,8 @@
       val = Vfontification_functions;
       specbind (Qfontification_functions, Qnil);
 
+      xassert (it->end_charpos == ZV);
+      
       if (!CONSP (val) || EQ (XCAR (val), Qlambda))
 	safe_call1 (val, pos);
       else
@@ -3376,6 +3378,13 @@
 
       unbind_to (count, Qnil);
 
+      /* The fontification code may have added/removed text.
+	 It could do even a lot worse, but let's at least protect against
+	 the most obvious case where only the text past `pos' gets changed',
+	 as is/was done in grep.el where some escapes sequences are turned
+	 into face properties (bug#7876).  */
+      it->end_charpos = ZV;
+      
       /* Return HANDLED_RECOMPUTE_PROPS only if function fontified
 	 something.  This avoids an endless loop if they failed to
 	 fontify the text for which reason ever.  */