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

From: Thiago Melo <[email-masked]>
Date: Thu, 25 May 2023 18:17:11 +0000

Sorry, my last patch had a misplaced `#if' block  at xterm.h, that I
only noticed after trying to build emacs with gtk. I've attached an
updated version here.
From a0c1c8c1c85aee0810c42b8721e3aad0fc95032a Mon Sep 17 00:00:00 2001
From: Thiago Melo <[email-masked]>
Date: Thu, 25 May 2023 19:15:39 +0200
Subject: [PATCH] Fix Bug#63589.

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

diff --git a/src/xterm.c b/src/xterm.c
index e981a36..d35b35c 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -5806,10 +5806,15 @@ 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);
+	if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS)
+	  eassert (FRAME_DISPLAY_INFO (f)->cairo_device
+		   == cairo_surface_get_device (surface));
+	}
       else
 #endif
 	surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
@@ -30504,6 +30509,27 @@ #define NUM_ARGV 10
 
   unblock_input ();
 
+#ifdef USE_CAIRO_XCB_SURFACE
+  /* Store reference to the cairo device for this display, to ensure
+     that it is destroyed before closing connection (Bug#63589).
+     For that, we create a drawable, an XCB surface for that drawable,
+     and then we get the device reference from there.  */
+  Pixmap drawable;
+  cairo_surface_t *surface;
+
+  drawable = XCreatePixmap (dpyinfo->display, dpyinfo->root_window,
+			    1, 1, dpyinfo->n_planes);
+  surface = cairo_xcb_surface_create (dpyinfo->xcb_connection, drawable,
+				      dpyinfo->xcb_visual, 1, 1);
+
+  if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS)
+    {
+      dpyinfo->cairo_device = cairo_device_reference (cairo_surface_get_device (surface));
+      cairo_surface_destroy (surface);
+    }
+  XFreePixmap (dpyinfo->display, drawable);
+#endif
+
 #if defined HAVE_XFIXES && defined USE_XCB
   SAFE_FREE ();
 #endif
@@ -30783,6 +30809,17 @@ x_delete_terminal (struct terminal *terminal)
     xim_close_dpy (dpyinfo);
 #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
+
   /* Normally, the display is available...  */
   if (dpyinfo->display)
     {
diff --git a/src/xterm.h b/src/xterm.h
index 8834346..4793908 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
+     in cairo-xcb builds.  */
+  cairo_device_t *cairo_device;
+#endif
 };
 
 #ifdef HAVE_X_I18N
-- 
2.39.2