From 2f1abeeb1a42caebc20279aa89a9423a3d60109b Mon Sep 17 00:00:00 2001 From: Michael Grant Date: Sun, 20 Sep 2026 22:37:59 +0100 Subject: [PATCH] window: fix use-after-free destroying a zoomed window window_destroy() called window_unzoom() before tearing anything down. layout_fix_panes() inside that resizes panes, which fires the pane-resized hook; the hook's event payload takes and drops its own reference on the window, and since w->references was already 0 at that point, dropping it reached 0 again and re-entered window_destroy() from inside itself - freeing w and its panes while the outer call was still using them. Pin the window's reference count across window_unzoom() so that reentrant drop can't reach zero again. Co-Authored-By: Claude Sonnet 5 --- window.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/window.c b/window.c index 82aa8b499..e92051016 100644 --- a/window.c +++ b/window.c @@ -452,7 +452,18 @@ window_destroy(struct window *w) { log_debug("window @%u destroyed (%d references)", w->id, w->references); + /* + * Pin the window while unzooming: layout_fix_panes() resizes panes, + * which fires the pane-resized hook, and its event payload takes and + * drops its own reference on the window. references is already 0 + * here, so that reference reaching 0 again would call window_destroy() + * a second time from inside this call, freeing w (and its panes) + * out from under the rest of this function. + */ + w->references++; window_unzoom(w, 0); + w->references--; + RB_REMOVE(windows, &windows, w); layout_free_cell(w->layout_root, 0);