From 90937cbfe48229028d839a5e8c5815020e84b235 Mon Sep 17 00:00:00 2001 From: Philip Date: Sat, 5 Sep 2015 11:08:57 +0300 Subject: [PATCH] Fix segfaults due to using a stale face ID * src/xdisp.c (forget_escape_and_glyphless_faces): New function. (display_echo_area_1, redisplay_internal): Call it to avoid reusing stale face IDs for 'escape-glyph' and 'glyphless-char' faces, which could case a segfault if the frame's face cache was freed since the last redisplay. (Bug#21394) * src/xfaces.c (free_realized_faces): Call forget_escape_and_glyphless_faces. * src/dispextern.h (forget_escape_and_glyphless_faces): Add prototype. Copyright-paperwork-exempt: yes --- src/dispextern.h | 1 + src/xdisp.c | 22 ++++++++++++++++++---- src/xfaces.c | 2 ++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index 37ebab04ddf..e5adeab0dc0 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3245,6 +3245,7 @@ extern ptrdiff_t compute_display_string_end (ptrdiff_t, struct bidi_string_data *); extern void produce_stretch_glyph (struct it *); extern int merge_glyphless_glyph_face (struct it *); +extern void forget_escape_and_glyphless_faces (void); extern void get_font_ascent_descent (struct font *, int *, int *); diff --git a/src/xdisp.c b/src/xdisp.c index 9ff9f6ce399..82931b88e1c 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -6787,6 +6787,18 @@ merge_glyphless_glyph_face (struct it *it) return face_id; } +/* Forget the `escape-glyph' and `glyphless-char' faces. This should + be called before redisplaying windows, and when the frame's face + cache is freed. */ +void +forget_escape_and_glyphless_faces (void) +{ + last_escape_glyph_frame = NULL; + last_escape_glyph_face_id = (1 << FACE_ID_BITS); + last_glyphless_glyph_frame = NULL; + last_glyphless_glyph_face_id = (1 << FACE_ID_BITS); +} + /* Load IT's display element fields with information about the next display element from the current position of IT. Value is false if end of buffer (or C string) is reached. */ @@ -10673,6 +10685,11 @@ display_echo_area_1 (ptrdiff_t a1, Lisp_Object a2) Lisp_Object window; struct text_pos start; + /* We are about to enter redisplay without going through + redisplay_internal, so we need to forget these faces by hand + here. */ + forget_escape_and_glyphless_faces (); + /* Do this before displaying, so that we have a large enough glyph matrix for the display. If we can't get enough space for the whole text, display the last N lines. That works by setting w->start. */ @@ -13326,10 +13343,7 @@ redisplay_internal (void) sw = w; pending = false; - last_escape_glyph_frame = NULL; - last_escape_glyph_face_id = (1 << FACE_ID_BITS); - last_glyphless_glyph_frame = NULL; - last_glyphless_glyph_face_id = (1 << FACE_ID_BITS); + forget_escape_and_glyphless_faces (); /* If face_change, init_iterator will free all realized faces, which includes the faces referenced from current matrices. So, we diff --git a/src/xfaces.c b/src/xfaces.c index d89adca8c57..03032496381 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -4173,6 +4173,8 @@ free_realized_faces (struct face_cache *c) c->faces_by_id[i] = NULL; } + /* Forget the escape-glyph and glyphless-char faces. */ + forget_escape_and_glyphless_faces (); c->used = 0; size = FACE_CACHE_BUCKETS_SIZE * sizeof *c->buckets; memset (c->buckets, 0, size); -- 2.39.2