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 *); #endif 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); +#endif 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 = { x_frame_parm_handlers, gui_produce_glyphs,