diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 96b2d8e215..004a00265a 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -247,6 +247,8 @@ static void emit_termrequest(void **argv) buf_T *buf = handle_get_buffer(buf_handle); if (!buf || buf->terminal == NULL) { // Terminal already closed. xfree(sequence); + kv_destroy(*pending_send); + xfree(pending_send); return; } Terminal *term = buf->terminal; @@ -1232,7 +1234,6 @@ void terminal_destroy(Terminal **termpp) kv_destroy(term->selection); kv_destroy(term->termrequest_buffer); vterm_free(term->vt); - xfree(term->pending.send); multiqueue_free(term->pending.events); xfree(term); *termpp = NULL; // coverity[dead-store] diff --git a/test/functional/terminal/parser_spec.lua b/test/functional/terminal/parser_spec.lua index 64aa3ea134..962ca24793 100644 --- a/test/functional/terminal/parser_spec.lua +++ b/test/functional/terminal/parser_spec.lua @@ -92,4 +92,17 @@ describe(':terminal', function() exec_lua([[return _G.osc10_response]]) ) end) + + it('does not leak pending TermRequest on buffer destroy #39332', function() + -- Send all OSC sequences in one exec_lua so that the event loop does not drain between the sends. + exec_lua(function(prefix, st) + local buf = vim.api.nvim_create_buf(false, true) + local chan = vim.api.nvim_open_term(buf, {}) + vim.api.nvim_create_autocmd('TermRequest', { buffer = buf, callback = function() end }) + vim.api.nvim_chan_send(chan, prefix .. '7;file:///a' .. st) + vim.api.nvim_chan_send(chan, prefix .. '7;file:///b' .. st) + vim.api.nvim_buf_delete(buf, { force = true }) + end, OSC_PREFIX, ST) + assert_alive() + end) end)