[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

--with-cairo Emacs server crash and fix

From: Liam Quinlan
Subject: --with-cairo Emacs server crash and fix
Date: Thu, 8 Aug 2019 03:01:39 -0400

If emacs is compiled for xwindows --with-cairo, then started with --daemon, and any packages that define a fringe bitmap are used (including builtin flymake), then 'define-fringe-bitmap' will be called from lisp during startup and attempt to define dynamic bitmaps when emacs has no active frame.

This is a problem because 'init_fringe_bitmap' (in src/fringe.c) relies on the SELECTED_FRAME macro in order to access a redisplay_interface structure and call 'rif->define_fringe_bitmap'.  Until a frame is created for a client session, this process will fail, causing emacs to skip calling 'rif->define_fringe_bitmap' (which should initialize 'fringe_bmp[which]' for cairo builds), but otherwise proceed as if the bitmap in question exists.  (note the code in question already contains the following comment: '/* XXX Is SELECTED_FRAME OK here? */' ... it is not.)

The upshot from there is, if[/when] emacs tries to *draw* these bitmaps, it pulls a null pointer out of 'fringe_bmp[which]' and hands it straight to libcairo.  Predictably, libcairo retaliates with the SEGV, and it's all over but the coredumping.

As best as I can tell, the following diff resolves the issue (at least as it manifests when using X; I haven't experimented with other configurations).  Style-wise it's a touch crude and hamfisted, but tbh trying to figure out the right approach for this codebase seemed to mean a whole lot of stumbling through giant briar patches of macro indirection, and I bailed.  Hopefully someone familiar with all that stuff can translate it readily enough.
[git diff against commit d5622eb6fff94714c5d5a64c98c5e02bc1be478c]

diff --git a/src/frame.h b/src/frame.h
index fa45a32d6b..94a880f4eb 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -1587,6 +1587,9 @@ #define EMACS_CLASS "Emacs"
 #if defined HAVE_X_WINDOWS
 extern void x_wm_set_icon_position (struct frame *, int, int);
+  #if defined USE_CAIRO
+  extern struct redisplay_interface x_redisplay_interface;
+  #endif
 #if !defined USE_X_TOOLKIT
 extern const char *x_get_resource_string (const char *, const char *);
diff --git a/src/fringe.c b/src/fringe.c
index d0d599223d..7a93afd418 100644
--- a/src/fringe.c
+++ b/src/fringe.c
@@ -1482,6 +1482,10 @@ init_fringe_bitmap (int which, struct fringe_bitmap *fb, int once_p)
       if (rif && rif->define_fringe_bitmap)
        rif->define_fringe_bitmap (which, fb->bits, fb->height, fb->width);
+#if (defined HAVE_X_WINDOWS) && (defined USE_CAIRO)
+      else
+        x_redisplay_interface.define_fringe_bitmap(which, fb->bits, fb->height, fb->width);
       fringe_bitmaps[which] = fb;
       if (which >= max_used_fringe_bitmap)
diff --git a/src/xterm.c b/src/xterm.c
index bbe68ef622..76fc5c21ac 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -13298,7 +13298,7 @@ x_activate_timeout_atimer (void)
 extern frame_parm_handler x_frame_parm_handlers[];
-static struct redisplay_interface x_redisplay_interface =
+struct redisplay_interface x_redisplay_interface =

reply via email to

[Prev in Thread] Current Thread [Next in Thread]