From: Eli Zaretskii Date: Sat, 17 Oct 2015 12:10:58 +0000 (+0300) Subject: Avoid crashes when redisplayng a window changes faces or fonts X-Git-Tag: emacs-25.0.90~1099 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=1431f667504b610471257802aa2f2f4f0d8443de;p=emacs.git Avoid crashes when redisplayng a window changes faces or fonts * src/xdisp.c (redisplay_internal): If redisplaying the selected window or one of the frames turns on the frame's 'redisplay' flag, redisplay again. (Bug#21428) * src/frame.c (x_set_font): Set the frame's 'fonts_changed' flag. --- diff --git a/src/frame.c b/src/frame.c index 98a7a57a988..6d596a48e23 100644 --- a/src/frame.c +++ b/src/frame.c @@ -3651,6 +3651,10 @@ x_set_font (struct frame *f, Lisp_Object arg, Lisp_Object oldval) /* Attempt to hunt down bug#16028. */ SET_FRAME_GARBAGED (f); + /* This is important if we are called by some Lisp as part of + redisplaying the frame, see redisplay_internal. */ + f->fonts_changed = true; + recompute_basic_faces (f); do_pending_window_change (0); diff --git a/src/xdisp.c b/src/xdisp.c index a793157f086..986e13f43b5 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -13810,6 +13810,7 @@ redisplay_internal (void) bool gcscrollbars /* Only GC scrollbars when we redisplay the whole frame. */ = f->redisplay || !REDISPLAY_SOME_P (); + bool f_redisplay_flag = f->redisplay; /* Mark all the scroll bars to be removed; we'll redeem the ones we want when we redisplay their windows. */ if (gcscrollbars && FRAME_TERMINAL (f)->condemn_scroll_bars_hook) @@ -13853,6 +13854,20 @@ redisplay_internal (void) goto retry_frame; } + /* If the frame's redisplay flag was not set before + we went about redisplaying its windows, but it is + set now, that means we employed some redisplay + optimizations inside redisplay_windows, and + bypassed producing some screen lines. But if + f->redisplay is now set, it might mean the old + faces are no longer valid (e.g., if redisplaying + some window called some Lisp which defined a new + face or redefined an existing face), so trying to + use them in update_frame will segfault. + Therefore, we must redisplay this frame. */ + if (!f_redisplay_flag && f->redisplay) + goto retry_frame; + /* Prevent various kinds of signals during display update. stdio is not robust about handling signals, which can cause an apparent I/O error. */ @@ -13906,8 +13921,10 @@ redisplay_internal (void) /* Compare desired and current matrices, perform output. */ update: - /* If fonts changed, display again. */ - if (sf->fonts_changed) + /* If fonts changed, display again. Likewise if redisplay_window_1 + above caused some change (e.g., a change in faces) that requires + considering the entire frame again. */ + if (sf->fonts_changed || sf->redisplay) goto retry; /* Prevent freeing of realized faces, since desired matrices are