diff options
| author | Eli Zaretskii | 2019-02-04 19:42:33 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2019-02-04 19:42:33 +0200 |
| commit | ef17247fe9cab2d59e470daad24314c868248b0a (patch) | |
| tree | bdbc2082ba69afdfa637d7dbe44e9b9803b21a0d /src | |
| parent | f33a5dc9475ae43bb2477e648befd6a893d216f1 (diff) | |
| download | emacs-ef17247fe9cab2d59e470daad24314c868248b0a.tar.gz emacs-ef17247fe9cab2d59e470daad24314c868248b0a.zip | |
Avoid segfaults due to image cache being cleared during redisplay
* src/xdisp.c (redisplay_internal): Set the
inhibit_clear_image_cache flag of a frame while its windows
are being redisplayed, and reset the flag after the call top
update_frame returns.
* src/image.c (clear_image_cache): Do nothing if the frame's
inhibit_clear_image_cache flag is set. (Bug#34256)
* src/frame.h (struct frame): New flag inhibit_clear_image_cache.
Diffstat (limited to 'src')
| -rw-r--r-- | src/frame.h | 4 | ||||
| -rw-r--r-- | src/image.c | 2 | ||||
| -rw-r--r-- | src/xdisp.c | 15 |
3 files changed, 19 insertions, 2 deletions
diff --git a/src/frame.h b/src/frame.h index ab3efdfa926..b7cbdd95571 100644 --- a/src/frame.h +++ b/src/frame.h | |||
| @@ -413,6 +413,10 @@ struct frame | |||
| 413 | /* Non-zero if this frame's faces need to be recomputed. */ | 413 | /* Non-zero if this frame's faces need to be recomputed. */ |
| 414 | bool_bf face_change : 1; | 414 | bool_bf face_change : 1; |
| 415 | 415 | ||
| 416 | /* Non-zero if this frame's image cache cannot be freed because the | ||
| 417 | frame is in the process of being redisplayed. */ | ||
| 418 | bool_bf inhibit_clear_image_cache : 1; | ||
| 419 | |||
| 416 | /* Bitfield area ends here. */ | 420 | /* Bitfield area ends here. */ |
| 417 | 421 | ||
| 418 | /* This frame's change stamp, set the last time window change | 422 | /* This frame's change stamp, set the last time window change |
diff --git a/src/image.c b/src/image.c index 57bbf3cdb93..642bf671520 100644 --- a/src/image.c +++ b/src/image.c | |||
| @@ -1554,7 +1554,7 @@ clear_image_cache (struct frame *f, Lisp_Object filter) | |||
| 1554 | { | 1554 | { |
| 1555 | struct image_cache *c = FRAME_IMAGE_CACHE (f); | 1555 | struct image_cache *c = FRAME_IMAGE_CACHE (f); |
| 1556 | 1556 | ||
| 1557 | if (c) | 1557 | if (c && !f->inhibit_clear_image_cache) |
| 1558 | { | 1558 | { |
| 1559 | ptrdiff_t i, nfreed = 0; | 1559 | ptrdiff_t i, nfreed = 0; |
| 1560 | 1560 | ||
diff --git a/src/xdisp.c b/src/xdisp.c index b5034b513e6..0bffaeb60bc 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -14431,7 +14431,17 @@ redisplay_internal (void) | |||
| 14431 | FRAME_TERMINAL (f)->condemn_scroll_bars_hook (f); | 14431 | FRAME_TERMINAL (f)->condemn_scroll_bars_hook (f); |
| 14432 | 14432 | ||
| 14433 | if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f)) | 14433 | if (FRAME_VISIBLE_P (f) && !FRAME_OBSCURED_P (f)) |
| 14434 | redisplay_windows (FRAME_ROOT_WINDOW (f)); | 14434 | { |
| 14435 | |||
| 14436 | /* Don't allow freeing images for this frame as long | ||
| 14437 | as the frame's update wasn't completed. This | ||
| 14438 | prevents crashes when some Lisp that runs from | ||
| 14439 | the various hooks or font-lock decides to clear | ||
| 14440 | the frame's image cache, when the images in that | ||
| 14441 | cache are referenced by the desired matrix. */ | ||
| 14442 | f->inhibit_clear_image_cache = true; | ||
| 14443 | redisplay_windows (FRAME_ROOT_WINDOW (f)); | ||
| 14444 | } | ||
| 14435 | /* Remember that the invisible frames need to be redisplayed next | 14445 | /* Remember that the invisible frames need to be redisplayed next |
| 14436 | time they're visible. */ | 14446 | time they're visible. */ |
| 14437 | else if (!REDISPLAY_SOME_P ()) | 14447 | else if (!REDISPLAY_SOME_P ()) |
| @@ -14512,6 +14522,7 @@ redisplay_internal (void) | |||
| 14512 | pending |= update_frame (f, false, false); | 14522 | pending |= update_frame (f, false, false); |
| 14513 | f->cursor_type_changed = false; | 14523 | f->cursor_type_changed = false; |
| 14514 | f->updated_p = true; | 14524 | f->updated_p = true; |
| 14525 | f->inhibit_clear_image_cache = false; | ||
| 14515 | } | 14526 | } |
| 14516 | } | 14527 | } |
| 14517 | } | 14528 | } |
| @@ -14539,6 +14550,7 @@ redisplay_internal (void) | |||
| 14539 | } | 14550 | } |
| 14540 | else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf)) | 14551 | else if (FRAME_VISIBLE_P (sf) && !FRAME_OBSCURED_P (sf)) |
| 14541 | { | 14552 | { |
| 14553 | sf->inhibit_clear_image_cache = true; | ||
| 14542 | displayed_buffer = XBUFFER (XWINDOW (selected_window)->contents); | 14554 | displayed_buffer = XBUFFER (XWINDOW (selected_window)->contents); |
| 14543 | /* Use list_of_error, not Qerror, so that | 14555 | /* Use list_of_error, not Qerror, so that |
| 14544 | we catch only errors and don't run the debugger. */ | 14556 | we catch only errors and don't run the debugger. */ |
| @@ -14594,6 +14606,7 @@ redisplay_internal (void) | |||
| 14594 | XWINDOW (selected_window)->must_be_updated_p = true; | 14606 | XWINDOW (selected_window)->must_be_updated_p = true; |
| 14595 | pending = update_frame (sf, false, false); | 14607 | pending = update_frame (sf, false, false); |
| 14596 | sf->cursor_type_changed = false; | 14608 | sf->cursor_type_changed = false; |
| 14609 | sf->inhibit_clear_image_cache = false; | ||
| 14597 | } | 14610 | } |
| 14598 | 14611 | ||
| 14599 | /* We may have called echo_area_display at the top of this | 14612 | /* We may have called echo_area_display at the top of this |