diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 7acf73ea0b..be8a87d389 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1904,18 +1904,21 @@ buf_T *buflist_new(char *ffname_arg, char *sfname_arg, linenr_T lnum, int flags) // buffer.) buf = NULL; if ((flags & BLN_CURBUF) && curbuf_reusable()) { + bufref_T bufref; + assert(curbuf != NULL); buf = curbuf; + set_bufref(&bufref, buf); // It's like this buffer is deleted. Watch out for autocommands that // change curbuf! If that happens, allocate a new buffer anyway. buf_freeall(buf, BFA_WIPE | BFA_DEL); - if (buf != curbuf) { // autocommands deleted the buffer! - return NULL; - } if (aborting()) { // autocmds may abort script processing xfree(ffname); return NULL; } + if (!bufref_valid(&bufref)) { + buf = NULL; // buf was deleted; allocate a new buffer + } } if (buf != curbuf || curbuf == NULL) { buf = xcalloc(1, sizeof(buf_T)); diff --git a/test/old/testdir/test_autocmd.vim b/test/old/testdir/test_autocmd.vim index b15a97d7e5..a35049d468 100644 --- a/test/old/testdir/test_autocmd.vim +++ b/test/old/testdir/test_autocmd.vim @@ -4342,4 +4342,29 @@ func Test_eventignorewin_non_current() %bw! endfunc +func Test_reuse_curbuf_leak() + new bar + let s:bar_buf = bufnr() + augroup testing + autocmd! + autocmd BufDelete * ++once let s:triggered = 1 | execute s:bar_buf 'buffer' + augroup END + enew + let empty_buf = bufnr() + + " Old curbuf should be reused, firing BufDelete. As BufDelete changes curbuf, + " reusing the buffer would fail and leak the ffname. + edit foo + call assert_equal(1, s:triggered) + " Wasn't reused because the buffer changed, but buffer "foo" is still created. + call assert_equal(1, bufexists(empty_buf)) + call assert_notequal(empty_buf, bufnr()) + call assert_equal('foo', bufname()) + call assert_equal('bar', bufname(s:bar_buf)) + + unlet! s:bar_buf s:triggered + call CleanUpTestAuGroup() + %bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab