fix(buffer): disable buffer-updates before removing from window #18933

There can be other places that access window buffer info (e.g.
`tabpagebuflist()`), so checking `w_closing` in `win_findbuf()` doesn't
solve the crash in all cases, and may also cause Nvim's behavior to
diverge from Vim.

Fix #14998
This commit is contained in:
zeertzjq 2022-06-13 06:02:00 +08:00 committed by GitHub
parent feba56af7d
commit 429c40cce3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 13 additions and 8 deletions

View File

@ -575,6 +575,10 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i
return false; return false;
} }
// Disable buffer-updates for the current buffer.
// No need to check `unload_buf`: in that case the function returned above.
buf_updates_unload(buf, false);
if (win != NULL // Avoid bogus clang warning. if (win != NULL // Avoid bogus clang warning.
&& win_valid_any_tab(win) && win_valid_any_tab(win)
&& win->w_buffer == buf) { && win->w_buffer == buf) {
@ -587,10 +591,6 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i
buf->b_nwindows--; buf->b_nwindows--;
} }
// Disable buffer-updates for the current buffer.
// No need to check `unload_buf`: in that case the function returned above.
buf_updates_unload(buf, false);
// Remove the buffer from the list. // Remove the buffer from the list.
if (wipe_buf) { if (wipe_buf) {
// Do not wipe out the buffer if it is used in a window. // Do not wipe out the buffer if it is used in a window.

View File

@ -7297,7 +7297,7 @@ void win_findbuf(typval_T *argvars, list_T *list)
int bufnr = tv_get_number(&argvars[0]); int bufnr = tv_get_number(&argvars[0]);
FOR_ALL_TAB_WINDOWS(tp, wp) { FOR_ALL_TAB_WINDOWS(tp, wp) {
if (!wp->w_closing && wp->w_buffer->b_fnum == bufnr) { if (wp->w_buffer->b_fnum == bufnr) {
tv_list_append_number(list, wp->handle); tv_list_append_number(list, wp->handle);
} }
} }

View File

@ -252,9 +252,8 @@ describe('lua buffer event callbacks: on_lines', function()
eq(2, meths.win_get_cursor(0)[1]) eq(2, meths.win_get_cursor(0)[1])
end) end)
it('does not SEGFAULT when calling win_findbuf in on_detach', function() it('does not SEGFAULT when accessing window buffer info in on_detach #14998', function()
local code = [[
exec_lua[[
local buf = vim.api.nvim_create_buf(false, false) local buf = vim.api.nvim_create_buf(false, false)
vim.cmd"split" vim.cmd"split"
@ -262,13 +261,19 @@ describe('lua buffer event callbacks: on_lines', function()
vim.api.nvim_buf_attach(buf, false, { vim.api.nvim_buf_attach(buf, false, {
on_detach = function(_, buf) on_detach = function(_, buf)
vim.fn.tabpagebuflist()
vim.fn.win_findbuf(buf) vim.fn.win_findbuf(buf)
end end
}) })
]] ]]
exec_lua(code)
command("q!") command("q!")
helpers.assert_alive() helpers.assert_alive()
exec_lua(code)
command("bd!")
helpers.assert_alive()
end) end)
it('#12718 lnume', function() it('#12718 lnume', function()