From 0c06da1f0a0ebe45c92d2c1d63121c6ead604fe5 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Sun, 3 Oct 2021 03:10:59 +0100 Subject: [PATCH] fix(nvim_open_win): crash if autocmds delete buffer/window #15549 win_set_buf can trigger autocmds if noautocmd=false. If they close the window, code afterwards will dereference the freed win_T* wp pointer. This interaction became possible after commit 1def3d1542d6a65f057e743faea39a760b50db87. The reason deleting curbuf crashes, and not the buf passed to `nvim_open_win`, is because the float initially edits curbuf (`win_init`) until it's later set to edit buf (windows from `:new` and `:split ` behave similiarly: approx. `:split`, then `:buffer `). `do_buffer` closes windows when their edited buffer is deleted (unless it's the only window; N/A for floats), so the float closes when curbuf is deleted, so we need to check `win_valid` after `win_set_buf` too. Closes #15548 --- src/nvim/api/vim.c | 7 ++++--- test/functional/ui/float_spec.lua | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 8e0502e03b..e2d7c03307 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1439,13 +1439,14 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config, Error *err if (enter) { win_enter(wp, false); } + // autocmds in win_enter or win_set_buf below may close the window + if (win_valid(wp) && buffer > 0) { + win_set_buf(wp->handle, buffer, fconfig.noautocmd, err); + } if (!win_valid(wp)) { api_set_error(err, kErrorTypeException, "Window was closed immediately"); return 0; } - if (buffer > 0) { - win_set_buf(wp->handle, buffer, fconfig.noautocmd, err); - } if (fconfig.style == kWinStyleMinimal) { win_set_minimal_style(wp); diff --git a/test/functional/ui/float_spec.lua b/test/functional/ui/float_spec.lua index 2e17aa68b2..79f308cf26 100644 --- a/test/functional/ui/float_spec.lua +++ b/test/functional/ui/float_spec.lua @@ -109,6 +109,21 @@ describe('float window', function() assert_alive() end) + it('closed immediately by autocmd after win_enter #15548', function() + eq('Error executing lua: [string ""]:0: Window was closed immediately', + pcall_err(exec_lua, [[ + vim.cmd "autocmd BufLeave * ++once quit!" + local buf = vim.api.nvim_create_buf(true, true) + vim.api.nvim_open_win(buf, true, { + relative = "win", + row = 0, col = 0, + width = 1, height = 1, + noautocmd = false, + }) + ]])) + assert_alive() + end) + it('opened with correct height', function() local height = exec_lua([[ vim.api.nvim_set_option("winheight", 20)