From 7e50eb0e835cc052a5fdda1765b101a80c07a7d9 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 11 Feb 2026 08:30:37 +0000 Subject: [PATCH] Make paste_get_top return a copy of the buffer name which is more sensible and avoids a double free pointed out by DongHan Kim. --- cmd-set-buffer.c | 40 +++++++++++++++++++++------------------- paste.c | 4 ++-- tmux.h | 2 +- window-copy.c | 5 +++-- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 0b0ec3a2..5b66dbee 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -58,29 +58,31 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item) struct args *args = cmd_get_args(self); struct client *tc = cmdq_get_target_client(item); struct paste_buffer *pb; - char *bufdata, *cause; - const char *bufname, *olddata; - size_t bufsize, newsize; + char *bufname, *bufdata = NULL, *cause = NULL; + const char *olddata; + size_t bufsize = 0, newsize; - bufname = args_get(args, 'b'); - if (bufname == NULL) + if (args_get(args, 'b') == NULL) pb = NULL; - else + else { + bufname = xstrdup(args_get(args, 'b')); pb = paste_get_name(bufname); + } if (cmd_get_entry(self) == &cmd_delete_buffer_entry) { if (pb == NULL) { if (bufname != NULL) { cmdq_error(item, "unknown buffer: %s", bufname); - return (CMD_RETURN_ERROR); + goto fail; } pb = paste_get_top(&bufname); } if (pb == NULL) { cmdq_error(item, "no buffer"); - return (CMD_RETURN_ERROR); + goto fail; } paste_free(pb); + free(bufname); return (CMD_RETURN_NORMAL); } @@ -88,32 +90,28 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item) if (pb == NULL) { if (bufname != NULL) { cmdq_error(item, "unknown buffer: %s", bufname); - return (CMD_RETURN_ERROR); + goto fail; } pb = paste_get_top(&bufname); } if (pb == NULL) { cmdq_error(item, "no buffer"); - return (CMD_RETURN_ERROR); + goto fail; } if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) { cmdq_error(item, "%s", cause); - free(cause); - return (CMD_RETURN_ERROR); + goto fail; } return (CMD_RETURN_NORMAL); } if (args_count(args) != 1) { cmdq_error(item, "no data specified"); - return (CMD_RETURN_ERROR); + goto fail; } if ((newsize = strlen(args_string(args, 0))) == 0) return (CMD_RETURN_NORMAL); - bufsize = 0; - bufdata = NULL; - if (args_has(args, 'a') && pb != NULL) { olddata = paste_buffer_data(pb, &bufsize); bufdata = xmalloc(bufsize); @@ -126,12 +124,16 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item) if (paste_set(bufdata, bufsize, bufname, &cause) != 0) { cmdq_error(item, "%s", cause); - free(bufdata); - free(cause); - return (CMD_RETURN_ERROR); + goto fail; } if (args_has(args, 'w') && tc != NULL) tty_set_selection(&tc->tty, "", bufdata, bufsize); return (CMD_RETURN_NORMAL); + +fail: + free(bufdata); + free(bufname); + free(cause); + return (CMD_RETURN_ERROR); } diff --git a/paste.c b/paste.c index a35bc4b3..509e2aa3 100644 --- a/paste.c +++ b/paste.c @@ -107,7 +107,7 @@ paste_is_empty(void) /* Get the most recent automatic buffer. */ struct paste_buffer * -paste_get_top(const char **name) +paste_get_top(char **name) { struct paste_buffer *pb; @@ -117,7 +117,7 @@ paste_get_top(const char **name) if (pb == NULL) return (NULL); if (name != NULL) - *name = pb->name; + *name = xstrdup(pb->name); return (pb); } diff --git a/tmux.h b/tmux.h index fdbf55c1..4c40cf83 100644 --- a/tmux.h +++ b/tmux.h @@ -2320,7 +2320,7 @@ time_t paste_buffer_created(struct paste_buffer *); const char *paste_buffer_data(struct paste_buffer *, size_t *); struct paste_buffer *paste_walk(struct paste_buffer *); int paste_is_empty(void); -struct paste_buffer *paste_get_top(const char **); +struct paste_buffer *paste_get_top(char **); struct paste_buffer *paste_get_name(const char *); void paste_free(struct paste_buffer *); void paste_add(const char *, char *, size_t); diff --git a/window-copy.c b/window-copy.c index 04f62643..f3a8507d 100644 --- a/window-copy.c +++ b/window-copy.c @@ -5052,9 +5052,9 @@ static void window_copy_append_selection(struct window_mode_entry *wme) { struct window_pane *wp = wme->wp; - char *buf; + char *buf, *bufname = NULL; struct paste_buffer *pb; - const char *bufdata, *bufname = NULL; + const char *bufdata; size_t len, bufsize; struct screen_write_ctx ctx; @@ -5079,6 +5079,7 @@ window_copy_append_selection(struct window_mode_entry *wme) } if (paste_set(buf, len, bufname, NULL) != 0) free(buf); + free(bufname); } static void