From 0985de0bc6fbfb7778b95803beb3f0c22734db84 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 12 Oct 2026 18:23:25 +0000 Subject: [PATCH 1/2] For tree mode, hold a reference to prompt and other bits across command to avoid crashing when killing the session with the mode's pane. GitHub issue 5728. --- mode-tree.c | 35 ++++++++++++++++++++--------------- window-tree.c | 12 +++++------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/mode-tree.c b/mode-tree.c index 222047f61..011294aec 100644 --- a/mode-tree.c +++ b/mode-tree.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mode-tree.c,v 1.103 2026/09/24 18:59:00 nicm Exp $ */ +/* $OpenBSD: mode-tree.c,v 1.104 2026/10/12 18:23:25 nicm Exp $ */ /* * Copyright (c) 2017 Nicholas Marriott @@ -701,8 +701,17 @@ mode_tree_build(struct mode_tree_data *mtd) static void mode_tree_remove_ref(struct mode_tree_data *mtd) { - if (--mtd->references == 0) - free(mtd); + if (--mtd->references != 0) + return; + + mode_tree_clear_prompt(mtd); + mode_tree_free_items(&mtd->children); + mode_tree_clear_lines(mtd); + screen_free(&mtd->screen); + + free(mtd->search); + free(mtd->filter); + free(mtd); } void @@ -713,14 +722,6 @@ mode_tree_free(struct mode_tree_data *mtd) if (mtd->zoomed == 0) server_unzoom_window(wp->window); - mode_tree_clear_prompt(mtd); - mode_tree_free_items(&mtd->children); - mode_tree_clear_lines(mtd); - screen_free(&mtd->screen); - - free(mtd->search); - free(mtd->filter); - mtd->dead = 1; mode_tree_remove_ref(mtd); } @@ -1095,7 +1096,7 @@ mode_tree_prompt_accept(struct cmdq_item *item, void *data) struct client *c = cmdq_get_client(item); key_code key = 'y'; - if (mtd->prompt != NULL && c != NULL) + if (!mtd->dead && mtd->prompt != NULL && c != NULL) mode_tree_key(mtd, c, &key, NULL, NULL, NULL); mode_tree_remove_ref(mtd); @@ -1122,7 +1123,6 @@ mode_tree_prompt_free_callback(void *data) mtp->mtd->prompt_data = NULL; if (mtp->freecb != NULL) mtp->freecb(mtp->data); - mode_tree_remove_ref(mtp->mtd); free(mtp); } @@ -1152,8 +1152,6 @@ mode_tree_set_prompt(struct mode_tree_data *mtd, struct client *c, mtp->inputcb = inputcb; mtp->freecb = freecb; mtp->data = data; - - mtd->references++; mtd->prompt_top = options_get_number(oo, "status-position") == 0; memset(&pd, 0, sizeof pd); @@ -1524,6 +1522,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, if (mtd->prompt != NULL) { redraw = 0; prompt = mtd->prompt; + mtd->references++; mtp = mtd->prompt_data; if (mtp != NULL) @@ -1548,6 +1547,11 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, } } else result = prompt_key(prompt, *key, &redraw); + if (mtd->dead) { + mode_tree_remove_ref(mtd); + *key = KEYC_NONE; + return (1); + } if (mtd->prompt_data == mtp && mtp != NULL) mtp->c = NULL; @@ -1563,6 +1567,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, mode_tree_draw(mtd); mtd->wp->flags |= PANE_REDRAW; } + mode_tree_remove_ref(mtd); if (result != PROMPT_KEY_NOT_HANDLED) { *key = KEYC_NONE; return (0); diff --git a/window-tree.c b/window-tree.c index 49f9bbecc..b6388d92d 100644 --- a/window-tree.c +++ b/window-tree.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window-tree.c,v 1.96 2026/08/25 07:23:30 nicm Exp $ */ +/* $OpenBSD: window-tree.c,v 1.97 2026/10/12 18:23:25 nicm Exp $ */ /* * Copyright (c) 2017 Nicholas Marriott @@ -1344,12 +1344,10 @@ window_tree_kill_current_callback(struct client *c, void *modedata, if (tolower((u_char) s[0]) != 'y' || s[1] != '\0') return (PROMPT_CLOSE); + data->references++; window_tree_kill_each(data, mode_tree_get_current(mtd), c, KEYC_NONE); server_renumber_all(); - - data->references++; cmdq_append(c, cmdq_get_callback(window_tree_command_done, data)); - return (PROMPT_CLOSE); } @@ -1365,12 +1363,10 @@ window_tree_kill_tagged_callback(struct client *c, void *modedata, if (tolower((u_char) s[0]) != 'y' || s[1] != '\0') return (PROMPT_CLOSE); + data->references++; mode_tree_each_tagged(mtd, window_tree_kill_each, c, KEYC_NONE, 1); server_renumber_all(); - - data->references++; cmdq_append(c, cmdq_get_callback(window_tree_command_done, data)); - return (PROMPT_CLOSE); } @@ -1453,6 +1449,8 @@ window_tree_key(struct window_mode_entry *wme, struct client *c, item = mode_tree_get_current(data->data); finished = mode_tree_key(data->data, c, &key, m, &x, &y); + if (data->dead) + return; again: if (item != (new_item = mode_tree_get_current(data->data))) { From e2eb6b7d87aa7eb6e049b5d9658f489da02234ed Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 12 Oct 2026 18:47:52 +0000 Subject: [PATCH 2/2] Add a flag to mark screen_write_ctx as coming from pane input and change a function argument. --- input.c | 5 ++++- screen-write.c | 17 +++++++++-------- tmux.h | 3 ++- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/input.c b/input.c index 0d850e732..8ab63f5f6 100644 --- a/input.c +++ b/input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: input.c,v 1.274 2026/10/12 17:04:48 nicm Exp $ */ +/* $OpenBSD: input.c,v 1.275 2026/10/12 18:47:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -936,6 +936,7 @@ input_reset(struct input_ctx *ictx, int clear) screen_write_start_pane(sctx, wp, &wp->base); else screen_write_start(sctx, &wp->base); + sctx->flags |= SCREEN_WRITE_INPUT; screen_write_reset(sctx); screen_write_stop(sctx); } @@ -1064,6 +1065,7 @@ input_parse_buffer(struct window_pane *wp, const u_char *buf, size_t len) screen_write_start_pane(sctx, wp, &wp->base); else screen_write_start(sctx, &wp->base); + sctx->flags |= SCREEN_WRITE_INPUT; log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id, ictx->state->name, len, (int)len, buf); @@ -1083,6 +1085,7 @@ input_parse_screen(struct input_ctx *ictx, struct screen *s, return; screen_write_start_callback(sctx, s, cb, arg); + sctx->flags |= SCREEN_WRITE_INPUT; input_parse(ictx, buf, len); screen_write_stop(sctx); } diff --git a/screen-write.c b/screen-write.c index b37dd6283..8fda18fa1 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1,4 +1,4 @@ -/* $OpenBSD: screen-write.c,v 1.299 2026/10/05 08:41:23 nicm Exp $ */ +/* $OpenBSD: screen-write.c,v 1.300 2026/10/12 18:47:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -2564,8 +2564,9 @@ screen_write_collect_insert_clear(struct screen_write_ctx *ctx, u_int px, * background so the columns it covered do not lose their colour. */ static void -screen_write_clear_cell(struct grid *gd, u_int px, u_int py) +screen_write_clear_cell(struct screen_write_ctx *ctx, u_int px, u_int py) { + struct grid *gd = ctx->s->grid; struct grid_cell gc; int bg; @@ -2630,7 +2631,7 @@ screen_write_collect_end(struct screen_write_ctx *ctx) grid_view_get_cell(s->grid, xx, s->cy, &gc); if (~gc.flags & GRID_FLAG_PADDING) break; - screen_write_clear_cell(s->grid, xx, s->cy); + screen_write_clear_cell(ctx, xx, s->cy); log_debug("%s: padding erased (before) at %u (cx %u)", __func__, xx, s->cx); } @@ -2639,7 +2640,7 @@ screen_write_collect_end(struct screen_write_ctx *ctx) grid_view_get_cell(s->grid, 0, s->cy, &gc); if (gc.data.width > 1 || (gc.flags & GRID_FLAG_PADDING)) { - screen_write_clear_cell(s->grid, xx, s->cy); + screen_write_clear_cell(ctx, xx, s->cy); log_debug("%s: padding erased (before) at %u " "(cx %u)", __func__, xx, s->cx); } @@ -2658,7 +2659,7 @@ screen_write_collect_end(struct screen_write_ctx *ctx) grid_view_get_cell(s->grid, xx, s->cy, &gc); if (~gc.flags & GRID_FLAG_PADDING) break; - screen_write_clear_cell(s->grid, xx, s->cy); + screen_write_clear_cell(ctx, xx, s->cy); log_debug("%s: padding erased (after) at %u (cx %u)", __func__, xx, s->cx); } @@ -3085,12 +3086,12 @@ screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc, if (~tmp_gc.flags & GRID_FLAG_PADDING) break; log_debug("%s: padding at %u,%u", __func__, xx, s->cy); - screen_write_clear_cell(gd, xx, s->cy); + screen_write_clear_cell(ctx, xx, s->cy); } /* Overwrite the character at the start of this padding. */ log_debug("%s: character at %u,%u", __func__, xx, s->cy); - screen_write_clear_cell(gd, xx, s->cy); + screen_write_clear_cell(ctx, xx, s->cy); done = 1; } @@ -3108,7 +3109,7 @@ screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc, break; log_debug("%s: overwrite at %u,%u", __func__, xx, s->cy); - screen_write_clear_cell(gd, xx, s->cy); + screen_write_clear_cell(ctx, xx, s->cy); done = 1; } } diff --git a/tmux.h b/tmux.h index b74ac1889..8011b26e7 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1457 2026/10/12 12:35:03 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1458 2026/10/12 18:47:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -1101,6 +1101,7 @@ struct screen_write_ctx { #define SCREEN_WRITE_SYNC 0x1 #define SCREEN_WRITE_OBSCURED 0x2 #define SCREEN_WRITE_CHECKED_IF_OBSCURED 0x4 +#define SCREEN_WRITE_INPUT 0x8 screen_write_init_ctx_cb init_ctx_cb; void *arg;