Merge remote-tracking branch 'refs/remotes/tmux-openbsd/master'

* refs/remotes/tmux-openbsd/master:
  Add a flag to mark screen_write_ctx as coming from pane input and change a function argument.
  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.
This commit is contained in:
tmux update bot
2026-10-13 01:00:12 +00:00
5 changed files with 40 additions and 32 deletions

View File

@@ -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 <nicholas.marriott@gmail.com> * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -936,6 +936,7 @@ input_reset(struct input_ctx *ictx, int clear)
screen_write_start_pane(sctx, wp, &wp->base); screen_write_start_pane(sctx, wp, &wp->base);
else else
screen_write_start(sctx, &wp->base); screen_write_start(sctx, &wp->base);
sctx->flags |= SCREEN_WRITE_INPUT;
screen_write_reset(sctx); screen_write_reset(sctx);
screen_write_stop(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); screen_write_start_pane(sctx, wp, &wp->base);
else else
screen_write_start(sctx, &wp->base); screen_write_start(sctx, &wp->base);
sctx->flags |= SCREEN_WRITE_INPUT;
log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id, log_debug("%s: %%%u %s, %zu bytes: %.*s", __func__, wp->id,
ictx->state->name, len, (int)len, buf); ictx->state->name, len, (int)len, buf);
@@ -1083,6 +1085,7 @@ input_parse_screen(struct input_ctx *ictx, struct screen *s,
return; return;
screen_write_start_callback(sctx, s, cb, arg); screen_write_start_callback(sctx, s, cb, arg);
sctx->flags |= SCREEN_WRITE_INPUT;
input_parse(ictx, buf, len); input_parse(ictx, buf, len);
screen_write_stop(sctx); screen_write_stop(sctx);
} }

View File

@@ -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 <nicholas.marriott@gmail.com> * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -701,8 +701,17 @@ mode_tree_build(struct mode_tree_data *mtd)
static void static void
mode_tree_remove_ref(struct mode_tree_data *mtd) mode_tree_remove_ref(struct mode_tree_data *mtd)
{ {
if (--mtd->references == 0) if (--mtd->references != 0)
free(mtd); 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 void
@@ -713,14 +722,6 @@ mode_tree_free(struct mode_tree_data *mtd)
if (mtd->zoomed == 0) if (mtd->zoomed == 0)
server_unzoom_window(wp->window); 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; mtd->dead = 1;
mode_tree_remove_ref(mtd); 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); struct client *c = cmdq_get_client(item);
key_code key = 'y'; 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_key(mtd, c, &key, NULL, NULL, NULL);
mode_tree_remove_ref(mtd); mode_tree_remove_ref(mtd);
@@ -1122,7 +1123,6 @@ mode_tree_prompt_free_callback(void *data)
mtp->mtd->prompt_data = NULL; mtp->mtd->prompt_data = NULL;
if (mtp->freecb != NULL) if (mtp->freecb != NULL)
mtp->freecb(mtp->data); mtp->freecb(mtp->data);
mode_tree_remove_ref(mtp->mtd);
free(mtp); free(mtp);
} }
@@ -1152,8 +1152,6 @@ mode_tree_set_prompt(struct mode_tree_data *mtd, struct client *c,
mtp->inputcb = inputcb; mtp->inputcb = inputcb;
mtp->freecb = freecb; mtp->freecb = freecb;
mtp->data = data; mtp->data = data;
mtd->references++;
mtd->prompt_top = options_get_number(oo, "status-position") == 0; mtd->prompt_top = options_get_number(oo, "status-position") == 0;
memset(&pd, 0, sizeof pd); 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) { if (mtd->prompt != NULL) {
redraw = 0; redraw = 0;
prompt = mtd->prompt; prompt = mtd->prompt;
mtd->references++;
mtp = mtd->prompt_data; mtp = mtd->prompt_data;
if (mtp != NULL) if (mtp != NULL)
@@ -1548,6 +1547,11 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
} }
} else } else
result = prompt_key(prompt, *key, &redraw); 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) if (mtd->prompt_data == mtp && mtp != NULL)
mtp->c = 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); mode_tree_draw(mtd);
mtd->wp->flags |= PANE_REDRAW; mtd->wp->flags |= PANE_REDRAW;
} }
mode_tree_remove_ref(mtd);
if (result != PROMPT_KEY_NOT_HANDLED) { if (result != PROMPT_KEY_NOT_HANDLED) {
*key = KEYC_NONE; *key = KEYC_NONE;
return (0); return (0);

View File

@@ -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 <nicholas.marriott@gmail.com> * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -2651,8 +2651,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. * background so the columns it covered do not lose their colour.
*/ */
static void 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; struct grid_cell gc;
int bg; int bg;
@@ -2717,7 +2718,7 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
grid_view_get_cell(s->grid, xx, s->cy, &gc); grid_view_get_cell(s->grid, xx, s->cy, &gc);
if (~gc.flags & GRID_FLAG_PADDING) if (~gc.flags & GRID_FLAG_PADDING)
break; 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)", log_debug("%s: padding erased (before) at %u (cx %u)",
__func__, xx, s->cx); __func__, xx, s->cx);
} }
@@ -2726,7 +2727,7 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
grid_view_get_cell(s->grid, 0, s->cy, &gc); grid_view_get_cell(s->grid, 0, s->cy, &gc);
if (gc.data.width > 1 || if (gc.data.width > 1 ||
(gc.flags & GRID_FLAG_PADDING)) { (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 " log_debug("%s: padding erased (before) at %u "
"(cx %u)", __func__, xx, s->cx); "(cx %u)", __func__, xx, s->cx);
} }
@@ -2750,7 +2751,7 @@ screen_write_collect_end(struct screen_write_ctx *ctx)
grid_view_get_cell(s->grid, xx, s->cy, &gc); grid_view_get_cell(s->grid, xx, s->cy, &gc);
if (~gc.flags & GRID_FLAG_PADDING) if (~gc.flags & GRID_FLAG_PADDING)
break; 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__, log_debug("%s: padding erased (after) at %u (cx %u)", __func__,
xx, s->cx); xx, s->cx);
} }
@@ -3177,12 +3178,12 @@ screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
if (~tmp_gc.flags & GRID_FLAG_PADDING) if (~tmp_gc.flags & GRID_FLAG_PADDING)
break; break;
log_debug("%s: padding at %u,%u", __func__, xx, s->cy); 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. */ /* Overwrite the character at the start of this padding. */
log_debug("%s: character at %u,%u", __func__, xx, s->cy); 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; done = 1;
} }
@@ -3200,7 +3201,7 @@ screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc,
break; break;
log_debug("%s: overwrite at %u,%u", __func__, xx, log_debug("%s: overwrite at %u,%u", __func__, xx,
s->cy); s->cy);
screen_write_clear_cell(gd, xx, s->cy); screen_write_clear_cell(ctx, xx, s->cy);
done = 1; done = 1;
} }
} }

3
tmux.h
View File

@@ -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 <nicholas.marriott@gmail.com> * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1135,6 +1135,7 @@ struct screen_write_ctx {
#define SCREEN_WRITE_SYNC 0x1 #define SCREEN_WRITE_SYNC 0x1
#define SCREEN_WRITE_OBSCURED 0x2 #define SCREEN_WRITE_OBSCURED 0x2
#define SCREEN_WRITE_CHECKED_IF_OBSCURED 0x4 #define SCREEN_WRITE_CHECKED_IF_OBSCURED 0x4
#define SCREEN_WRITE_INPUT 0x8
screen_write_init_ctx_cb init_ctx_cb; screen_write_init_ctx_cb init_ctx_cb;
void *arg; void *arg;

View File

@@ -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 <nicholas.marriott@gmail.com> * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1344,12 +1344,10 @@ window_tree_kill_current_callback(struct client *c, void *modedata,
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0') if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
return (PROMPT_CLOSE); return (PROMPT_CLOSE);
data->references++;
window_tree_kill_each(data, mode_tree_get_current(mtd), c, KEYC_NONE); window_tree_kill_each(data, mode_tree_get_current(mtd), c, KEYC_NONE);
server_renumber_all(); server_renumber_all();
data->references++;
cmdq_append(c, cmdq_get_callback(window_tree_command_done, data)); cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
return (PROMPT_CLOSE); 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') if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
return (PROMPT_CLOSE); return (PROMPT_CLOSE);
data->references++;
mode_tree_each_tagged(mtd, window_tree_kill_each, c, KEYC_NONE, 1); mode_tree_each_tagged(mtd, window_tree_kill_each, c, KEYC_NONE, 1);
server_renumber_all(); server_renumber_all();
data->references++;
cmdq_append(c, cmdq_get_callback(window_tree_command_done, data)); cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
return (PROMPT_CLOSE); 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); item = mode_tree_get_current(data->data);
finished = mode_tree_key(data->data, c, &key, m, &x, &y); finished = mode_tree_key(data->data, c, &key, m, &x, &y);
if (data->dead)
return;
again: again:
if (item != (new_item = mode_tree_get_current(data->data))) { if (item != (new_item = mode_tree_get_current(data->data))) {