commit 7297e9d339c64f2f2c57cb2cc57455c161ef78e5
parent d42fa1753adc18c4b22577724a804d556a16d736
Author: zeertzjq <zeertzjq@outlook.com>
Date: Mon, 5 Jan 2026 14:11:39 +0800
fix(terminal): crash when TermClose deletes other buffers
Problem: Crash when deleting terminal buffer and TermClose deletes
other buffers.
Solution: Close the terminal after restoring b_nwindows.
Diffstat:
2 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
@@ -648,10 +648,6 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i
return true;
}
- if (buf->terminal) {
- buf_close_terminal(buf);
- }
-
// Always remove the buffer when there is no file name.
if (buf->b_ffname == NULL) {
del_buf = true;
@@ -675,6 +671,15 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i
buf->b_nwindows = nwindows;
+ if (buf->terminal) {
+ buf_close_terminal(buf);
+ // Must check this before calling buf_freeall(), otherwise is_curbuf will be true
+ // in buf_freeall() but still false here, leading to a 0-line buffer.
+ if (buf == curbuf && !is_curbuf) {
+ return false;
+ }
+ }
+
buf_freeall(buf, ((del_buf ? BFA_DEL : 0)
+ (wipe_buf ? BFA_WIPE : 0)
+ (ignore_abort ? BFA_IGNORE_ABORT : 0)));
diff --git a/test/functional/autocmd/termxx_spec.lua b/test/functional/autocmd/termxx_spec.lua
@@ -45,6 +45,18 @@ describe('autocmd TermClose', function()
test_termclose_delete_own_buf()
end)
+ it('TermClose deleting all other buffers', function()
+ local oldbuf = api.nvim_get_current_buf()
+ -- The terminal process needs to keep running so that TermClose isn't triggered immediately.
+ api.nvim_set_option_value('shell', string.format('"%s" INTERACT', testprg('shell-test')), {})
+ command(('autocmd TermClose * bdelete! %d'):format(oldbuf))
+ command('horizontal terminal')
+ neq(oldbuf, api.nvim_get_current_buf())
+ command('bdelete!')
+ feed('<C-G>') -- This shouldn't crash due to having a 0-line buffer.
+ assert_alive()
+ end)
+
it('triggers when fast-exiting terminal job stops', function()
command('autocmd TermClose * let g:test_termclose = 23')
command('terminal')