From c291194a4e593bbbb91420e81fa0111508084448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Wed, 28 Jan 2026 09:44:57 +0100 Subject: [PATCH] wayland: wait for pre-apply damage thread before destroying a terminal instance It's possible, but unlikely, that we've pushed a "pre-apply damage" job to the renderer thread queue (or that we've pushed it, and the a thread is now working on it) when we shutdown a terminal instance. This is sometimes caught in an assertion in term_destroy(), where we check the queue length is 0. Other times, or in release builds, we might crash in the thread, or in the shutdown logic when freeing the buffer chains associated with the terminal instance. Fix by ensuring there's no pre-apply damage operation queued, or running, before shutting down a terminal instance. Closes #2263 --- CHANGELOG.md | 3 +++ render.c | 10 +++++----- render.h | 1 + wayland.c | 2 ++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce1a7d8c..cee4ddef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -126,10 +126,13 @@ application (kitty keyboard protocol only) ([#2257][2257]). * Crash when application emits sixel RA with a height of 0, a width > 0, and then starts writing sixel data ([#2267][2267]). +* Crash if shutting down terminal instance while a "pre-apply damage" + thread is running ([#2263][2263]). [2232]: https://codeberg.org/dnkl/foot/issues/2232 [2257]: https://codeberg.org/dnkl/foot/issues/2257 [2267]: https://codeberg.org/dnkl/foot/issues/2267 +[2263]: https://codeberg.org/dnkl/foot/issues/2263 ### Security diff --git a/render.c b/render.c index 86244434..3aa7d543 100644 --- a/render.c +++ b/render.c @@ -2288,8 +2288,8 @@ render_worker_thread(void *_ctx) return -1; } -static void -wait_for_preapply_damage(struct terminal *term) +void +render_wait_for_preapply_damage(struct terminal *term) { if (!term->render.preapply_last_frame_damage) return; @@ -3325,7 +3325,7 @@ grid_render(struct terminal *term) term->render.workers.preapplied_damage.buf != NULL)) { clock_gettime(CLOCK_MONOTONIC, &start_wait_preapply); - wait_for_preapply_damage(term); + render_wait_for_preapply_damage(term); clock_gettime(CLOCK_MONOTONIC, &stop_wait_preapply); } @@ -4401,7 +4401,7 @@ delayed_reflow_of_normal_grid(struct terminal *term) term->interactive_resizing.old_hide_cursor = false; /* Invalidate render pointers */ - wait_for_preapply_damage(term); + render_wait_for_preapply_damage(term); shm_unref(term->render.last_buf); term->render.last_buf = NULL; term->render.last_cursor.row = NULL; @@ -4976,7 +4976,7 @@ damage_view: tll_free(term->normal.scroll_damage); tll_free(term->alt.scroll_damage); - wait_for_preapply_damage(term); + render_wait_for_preapply_damage(term); shm_unref(term->render.last_buf); term->render.last_buf = NULL; term_damage_view(term); diff --git a/render.h b/render.h index e21eaca8..e6674ab2 100644 --- a/render.h +++ b/render.h @@ -49,3 +49,4 @@ struct csd_data { struct csd_data get_csd_data(const struct terminal *term, enum csd_surface surf_idx); void render_buffer_release_callback(struct buffer *buf, void *data); +void render_wait_for_preapply_damage(struct terminal *term); diff --git a/wayland.c b/wayland.c index 958e535d..59df991a 100644 --- a/wayland.c +++ b/wayland.c @@ -2129,6 +2129,8 @@ wayl_win_destroy(struct wl_window *win) struct terminal *term = win->term; + render_wait_for_preapply_damage(term); + if (win->csd.move_timeout_fd != -1) close(win->csd.move_timeout_fd);