Subject: bug#50571: 28.0.50; Redisplay segfaults with empty face cache

From: Eli Zaretskii <[email-masked]>
Date: Tue, 14 Sep 2021 16:33:43 +0300

> Date: Tue, 14 Sep 2021 16:03:02 +0300
> From: Eli Zaretskii <[email-masked]>
> Cc: [email-masked]
> 
> Thanks, I see the reason now.  It's because we allow to have arbitrary
> Lisp to be registered in jit-lock-functions, and then that arbitrary
> Lisp is called in the middle of redisplay, and in this case creates a
> whole new frame with faces.  As luck would have it, we decide right
> there and then perform routine maintenance and release all the faces
> on all the frames...
> 
> I'm thinking about the best solution for this.

Does the patch below give good results?

diff --git a/src/frame.h b/src/frame.h
index a8ad011..3dd7680 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -449,8 +449,8 @@ #define EMACS_FRAME_H
   /* Non-zero if this frame's faces need to be recomputed.  */
   bool_bf face_change : 1;
 
-  /* Non-zero if this frame's image cache cannot be freed because the
-     frame is in the process of being redisplayed.  */
+  /* Non-zero if this frame's image cache and face cache cannot be
+     freed because the frame is in the process of being redisplayed.  */
   bool_bf inhibit_clear_image_cache : 1;
 
   /* True when new_width or new_height were set by change_frame_size,
diff --git a/src/xdisp.c b/src/xdisp.c
index d30a685..2e72f6b 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -16061,12 +16061,13 @@ #define AINC(a,i)							\
 	      if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f))
 		{
 
-		  /* Don't allow freeing images for this frame as long
-		     as the frame's update wasn't completed.  This
-		     prevents crashes when some Lisp that runs from
-		     the various hooks or font-lock decides to clear
-		     the frame's image cache, when the images in that
-		     cache are referenced by the desired matrix.  */
+		  /* Don't allow freeing images and faces for this
+		     frame as long as the frame's update wasn't
+		     completed.  This prevents crashes when some Lisp
+		     that runs from the various hooks or font-lock
+		     decides to clear the frame's image cache and face
+		     cache, when the images and faces in those caches
+		     are referenced by the desired matrix.  */
 		  f->inhibit_clear_image_cache = true;
 		  redisplay_windows (FRAME_ROOT_WINDOW (f));
 		}
diff --git a/src/xfaces.c b/src/xfaces.c
index 2273fb4..aefed54 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -674,7 +674,8 @@ clear_face_cache (bool clear_fonts_p)
 	{
 	  struct frame *f = XFRAME (frame);
 	  if (FRAME_WINDOW_P (f)
-	      && FRAME_DISPLAY_INFO (f)->n_fonts > CLEAR_FONT_TABLE_NFONTS)
+	      && FRAME_DISPLAY_INFO (f)->n_fonts > CLEAR_FONT_TABLE_NFONTS
+	      && !f->inhibit_clear_image_cache)
 	    {
 	      clear_font_cache (f);
 	      free_all_realized_faces (frame);