From 4161023a63d68534d3e70931645ac82a88330334 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Thu, 1 Dec 2022 14:21:14 +0800 Subject: [PATCH] Fix crashes and memory leaks during display deinitialization * .dir-locals.el (c-mode): Add more noise macro names. * src/frame.c (delete_frame): Do not delete terminal if force is Qnoelisp. * src/xterm.c (x_wm_supports): Fix coding style. (x_delete_display): Delete the supported atoms list. (x_delete_terminal): Delete all terminals. Free the scratch cursor GC. --- .dir-locals.el | 3 ++- src/frame.c | 13 ++++++++++--- src/xterm.c | 31 ++++++++++++++++++++++++++++--- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/.dir-locals.el b/.dir-locals.el index f0ab46236f3..fc89dff87f2 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -11,7 +11,8 @@ (vc-prepare-patches-separately . nil))) (c-mode . ((c-file-style . "GNU") (c-noise-macro-names . ("INLINE" "NO_INLINE" "ATTRIBUTE_NO_SANITIZE_UNDEFINED" - "UNINIT" "CALLBACK" "ALIGN_STACK")) + "UNINIT" "CALLBACK" "ALIGN_STACK" "ATTRIBUTE_MALLOC" + "ATTRIBUTE_DEALLOC_FREE")) (electric-quote-comment . nil) (electric-quote-string . nil) (indent-tabs-mode . t) diff --git a/src/frame.c b/src/frame.c index b57b296be54..05106a6c759 100644 --- a/src/frame.c +++ b/src/frame.c @@ -2214,17 +2214,24 @@ delete_frame (Lisp_Object frame, Lisp_Object force) /* Since a similar behavior was observed on the Lucid and Motif builds (see Bug#5802, Bug#21509, Bug#23499, Bug#27816), we now don't delete the terminal for these builds either. */ - if (terminal->reference_count == 0 && - (terminal->type == output_x_window || terminal->type == output_pgtk)) + if (terminal->reference_count == 0 + && (terminal->type == output_x_window + || terminal->type == output_pgtk)) terminal->reference_count = 1; #endif /* USE_X_TOOLKIT || USE_GTK */ + if (terminal->reference_count == 0) { Lisp_Object tmp; XSETTERMINAL (tmp, terminal); kb = NULL; - Fdelete_terminal (tmp, NILP (force) ? Qt : force); + + /* If force is noelisp, the terminal is going away inside + x_delete_terminal, and a recursive call to Fdelete_terminal + is unsafe! */ + if (!EQ (force, Qnoelisp)) + Fdelete_terminal (tmp, NILP (force) ? Qt : force); } else kb = terminal->kboard; diff --git a/src/xterm.c b/src/xterm.c index 7eaf59d54b1..44fad6e8d59 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -26768,13 +26768,14 @@ x_wm_supports_1 (struct x_display_info *dpyinfo, Atom want_atom) if (rc != Success || actual_type != XA_ATOM || x_had_errors_p (dpy)) { - if (tmp_data) XFree (tmp_data); + if (tmp_data) + XFree (tmp_data); x_uncatch_errors (); unblock_input (); return false; } - dpyinfo->net_supported_atoms = (Atom *)tmp_data; + dpyinfo->net_supported_atoms = (Atom *) tmp_data; dpyinfo->nr_net_supported_atoms = actual_size; dpyinfo->net_supported_window = wmcheck_window; } @@ -30630,6 +30631,9 @@ x_delete_display (struct x_display_info *dpyinfo) } } + if (dpyinfo->net_supported_atoms) + XFree (dpyinfo->net_supported_atoms); + xfree (dpyinfo->color_names); xfree (dpyinfo->color_names_length); xfree (dpyinfo->x_id_name); @@ -30741,7 +30745,11 @@ static struct redisplay_interface x_redisplay_interface = void x_delete_terminal (struct terminal *terminal) { - struct x_display_info *dpyinfo = terminal->display_info.x; + struct x_display_info *dpyinfo; + struct frame *f; + Lisp_Object tail, frame; + + dpyinfo = terminal->display_info.x; /* Protect against recursive calls. delete_frame in delete_terminal calls us back when it deletes our last frame. */ @@ -30749,6 +30757,19 @@ x_delete_terminal (struct terminal *terminal) return; block_input (); + + /* Delete all remaining frames on the display that is going away. + Otherwise, font backends assume the display is still up, and + xftfont_end_for_frame crashes. */ + FOR_EACH_FRAME (tail, frame) + { + f = XFRAME (frame); + + if (FRAME_LIVE_P (f) && f->terminal == terminal) + /* Pass Qnoelisp rather than Qt. */ + delete_frame (frame, Qnoelisp); + } + #ifdef HAVE_X_I18N /* We must close our connection to the XIM server before closing the X display. */ @@ -30762,6 +30783,10 @@ x_delete_terminal (struct terminal *terminal) image_destroy_all_bitmaps (dpyinfo); XSetCloseDownMode (dpyinfo->display, DestroyAll); + /* Delete the scratch cursor GC, should it exist. */ + if (dpyinfo->scratch_cursor_gc) + XFreeGC (dpyinfo->display, dpyinfo->scratch_cursor_gc); + /* Get rid of any drag-and-drop operation that might be in progress as well. */ if ((x_dnd_in_progress || x_dnd_waiting_for_finish) -- 2.39.2