From fb0114e4caccbae9c27ea92d171bca624fc67803 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sat, 13 Apr 2024 19:43:40 +0800 Subject: [PATCH] Fix crash upon call to Fset_fontset_font after X server disconnect * src/image.c (free_image): * src/xfaces.c (free_realized_face): Handle scenarios where free_frame_faces is called with the display connection cut. * src/xterm.c (x_free_frame_resources): Call free_frame_faces unconditionally, lest fontsets for this dead frame contaminate Vfontset_list and produce crashes afterwards. (bug#66151) (cherry picked from commit 9fc698479feef6fa660ff13e21619ea50bd404df) --- src/image.c | 26 +++++++++++++++++++------- src/xfaces.c | 9 +++++++++ src/xterm.c | 15 +++++++++++---- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/image.c b/src/image.c index 216bdc1ee66..3968145728f 100644 --- a/src/image.c +++ b/src/image.c @@ -1699,14 +1699,26 @@ free_image (struct frame *f, struct image *img) c->images[img->id] = NULL; #if !defined USE_CAIRO && defined HAVE_XRENDER - if (img->picture) - XRenderFreePicture (FRAME_X_DISPLAY (f), img->picture); - if (img->mask_picture) - XRenderFreePicture (FRAME_X_DISPLAY (f), img->mask_picture); -#endif + /* FRAME_X_DISPLAY (f) could be NULL if this is being called from + the display IO error handler.*/ + + if (FRAME_X_DISPLAY (f)) + { + if (img->picture) + XRenderFreePicture (FRAME_X_DISPLAY (f), + img->picture); + if (img->mask_picture) + XRenderFreePicture (FRAME_X_DISPLAY (f), + img->mask_picture); + } +#endif /* !USE_CAIRO && HAVE_XRENDER */ + +#ifdef HAVE_X_WINDOWS + if (FRAME_X_DISPLAY (f)) +#endif /* HAVE_X_WINDOWS */ + /* Free resources, then free IMG. */ + img->type->free_img (f, img); - /* Free resources, then free IMG. */ - img->type->free_img (f, img); xfree (img->face_font_family); xfree (img); } diff --git a/src/xfaces.c b/src/xfaces.c index a558e7328c0..d4583e1a78f 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -4569,6 +4569,15 @@ free_realized_face (struct frame *f, struct face *face) /* Free fontset of FACE if it is ASCII face. */ if (face->fontset >= 0 && face == face->ascii_face) free_face_fontset (f, face); + +#ifdef HAVE_X_WINDOWS + /* This function might be called with the frame's display + connection deleted, in which event the callbacks below + should not be executed, as they generate X requests. */ + if (FRAME_X_DISPLAY (f)) + return; +#endif /* HAVE_X_WINDOWS */ + if (face->gc) { block_input (); diff --git a/src/xterm.c b/src/xterm.c index 5e5eb6269e4..e08ffd15b18 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -29428,6 +29428,17 @@ x_free_frame_resources (struct frame *f) xi_unlink_touch_points (f); #endif + /* We must free faces before destroying windows because some + font-driver (e.g. xft) access a window while finishing a face. + + This function must be called to remove this frame's fontsets from + Vfontset_list, and is itself responsible for not issuing X requests + if the connection has already been terminated. Otherwise, a future + call to a function that iterates over all existing fontsets might + crash, as they are not prepared to receive dead frames. + (bug#66151) */ + free_frame_faces (f); + /* If a display connection is dead, don't try sending more commands to the X server. */ if (dpyinfo->display) @@ -29437,10 +29448,6 @@ x_free_frame_resources (struct frame *f) if (f->pointer_invisible) XTtoggle_invisible_pointer (f, 0); - /* We must free faces before destroying windows because some - font-driver (e.g. xft) access a window while finishing a - face. */ - free_frame_faces (f); tear_down_x_back_buffer (f); if (f->output_data.x->icon_desc) -- 2.39.5