From 83037cf2185704a4b9a93c0883dc93226de86fdc Mon Sep 17 00:00:00 2001 From: luukvbaal Date: Sat, 14 Mar 2026 13:07:55 +0100 Subject: [PATCH] fix(messages): allocate message history kind string #38292 Problem: nvim_echo()->kind memory may be used after it is freed with :messages. Solution: Copy and free message kind string in message history. --- src/nvim/message.c | 3 ++- src/nvim/message_defs.h | 2 +- test/functional/api/vim_spec.lua | 9 +++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/nvim/message.c b/src/nvim/message.c index 088adde7c2..13c31a6137 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1153,7 +1153,7 @@ static void msg_hist_add_multihl(HlMessage msg, bool temp, MessageData *msg_data MessageHistoryEntry *entry = xmalloc(sizeof(MessageHistoryEntry)); entry->msg = msg; entry->temp = temp; - entry->kind = msg_ext_kind; + entry->kind = msg_ext_kind ? xstrdup(msg_ext_kind) : NULL; entry->prev = msg_hist_last; entry->next = NULL; // NOTE: this does not encode if the message was actually appended to the @@ -1195,6 +1195,7 @@ static void msg_hist_free_msg(MessageHistoryEntry *entry) msg_hist_temp = entry->next; } hl_msg_free(entry->msg); + xfree(entry->kind); xfree(entry); } diff --git a/src/nvim/message_defs.h b/src/nvim/message_defs.h index 68b6bf829b..6229c7f1af 100644 --- a/src/nvim/message_defs.h +++ b/src/nvim/message_defs.h @@ -23,7 +23,7 @@ typedef struct msg_hist { struct msg_hist *next; ///< Next message. struct msg_hist *prev; ///< Previous message. HlMessage msg; ///< Highlighted message. - const char *kind; ///< Message kind (for msg_ext) + char *kind; ///< Message kind (for msg_ext) bool temp; ///< Temporary message since last command ("g<") bool append; ///< Message should be appended to previous entry, as opposed ///< to on a new line (|ui-messages|->msg_show->append). diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 5e36a63264..92a7c8af25 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -3887,6 +3887,15 @@ describe('API', function() eq(4, api.nvim_echo({ { 'foo' } }, false, { id = 4 })) eq(5, api.nvim_echo({ { 'foo' } }, false, {})) end) + + it('no use-after-free for custom kind with :messages #38289', function() + exec_lua(function() + vim.api.nvim_echo({ { 'a' } }, true, { kind = 'foo' }) + vim.o.guicursor = '' -- pending mode update go brrr + vim.api.nvim__redraw({ flush = true }) -- ui_flush -> arena_mem_free go brrr + vim.cmd.messages() + end) + end) end) describe('nvim_open_term', function()