Subject: [PATCH] 29.0.91; crash after creating graphical frames via emacsclient when compiled with cairo-xcb

From: Thiago Melo <[email-masked]>
Date: Sat, 20 May 2023 22:47:17 +0000

Here's a patch to fix this issue. It was created on top of the
emacs-29 branch, commit 6b60c81.

It's based on the suggestion from the cairo mailing list (see the link
I sent in my original message here). It ensures that the cairo device
associated with the cairo-xcb surfaces in the display is destroyed
before closing the display.

It can probably be improved. It could even be extended to handle
cairo-xlib. In the cairo mailing list, they mentioned one corner case
where the xlib device is not properly destroyed: when cairo is
unloaded before the X11 connection is closed.
From d62b65d2a14aa348bd69bc7536357225f2571c18 Mon Sep 17 00:00:00 2001
From: Thiago Melo <[email-masked]>
Date: Sat, 20 May 2023 18:52:03 +0200
Subject: [PATCH] Fix Bug#63589.

---
 src/xterm.c | 16 ++++++++++++++++
 src/xterm.h |  6 ++++++
 2 files changed, 22 insertions(+)

diff --git a/src/xterm.c b/src/xterm.c
index e981a36..7ed4dfc 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -5806,10 +5806,16 @@ x_begin_cr_clip (struct frame *f, GC gc)
       cairo_surface_t *surface;
 #ifdef USE_CAIRO_XCB_SURFACE
       if (FRAME_DISPLAY_INFO (f)->xcb_visual)
+        {
 	surface = cairo_xcb_surface_create (FRAME_DISPLAY_INFO (f)->xcb_connection,
 					    (xcb_drawable_t) FRAME_X_RAW_DRAWABLE (f),
 					    FRAME_DISPLAY_INFO (f)->xcb_visual,
 					    width, height);
+	cairo_device_t *cairo_device = cairo_surface_get_device(surface);
+	if (cairo_device_get_type(cairo_device) == CAIRO_DEVICE_TYPE_XCB
+	    && !FRAME_DISPLAY_INFO (f)->cairo_device)
+	  FRAME_DISPLAY_INFO (f)->cairo_device = cairo_device_reference(cairo_device);
+        }
       else
 #endif
 	surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
@@ -30841,6 +30847,16 @@ x_delete_terminal (struct terminal *terminal)
 	 closing all the displays.  */
       XrmDestroyDatabase (dpyinfo->rdb);
 #endif
+#ifdef USE_CAIRO_XCB_SURFACE
+      /* Ensure that the cairo device is destroyed before closing
+         connection (Bug#63589).  */
+      if (dpyinfo->cairo_device)
+	{
+	  cairo_device_finish(dpyinfo->cairo_device);
+	  cairo_device_destroy(dpyinfo->cairo_device);
+	  dpyinfo->cairo_device = NULL;
+	}
+#endif
 #ifdef USE_GTK
       xg_display_close (dpyinfo->display);
 #else
diff --git a/src/xterm.h b/src/xterm.h
index 8834346..bdc5458 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -884,6 +884,12 @@ #define X_INVALID_WINDOW 0xffffffff
      server_time_monotonic_p will be true).  */
   int_fast64_t server_time_offset;
 #endif
+
+#if defined USE_XCB && defined USE_CAIRO_XCB
+  /* Cairo device associated with cairo surfaces in this display.
+     Required for proper cleanup before closing display connection.  */
+  cairo_device_t *cairo_device;
+#endif
 };
 
 #ifdef HAVE_X_I18N
-- 
2.39.2