Skip to content

Commit 0077282

Browse files
seandewarchrisbra
authored andcommitted
patch 9.1.1387: memory leak when buflist_new() fails to reuse curbuf
Problem: buflist_new() leaks ffname and fails to reuse curbuf when autocommands from buf_freeall change curbuf. Plus, a new buffer is not allocated in this case, despite what the comment above claims. Solution: Remove the condition so ffname is not leaked and so a new buffer is allocated like before v8.2.4791. It should not be possible for undo_ftplugin or buf_freeall autocommands to delete the buffer as they set b_locked, but to stay consistent with other uses of buf_freeall, guard against that anyway (Sean Dewar). Note that buf is set to NULL if it was deleted to guard against the (rare) possibility of messing up the "buf != curbuf" condition below if a new buffer happens to be allocated at the same address. closes: #17319 Signed-off-by: Sean Dewar <6256228+seandewar@users.noreply.github.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
1 parent c952fd1 commit 0077282

3 files changed

Lines changed: 32 additions & 2 deletions

File tree

src/buffer.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2220,20 +2220,23 @@ buflist_new(
22202220
buf = NULL;
22212221
if ((flags & BLN_CURBUF) && curbuf_reusable())
22222222
{
2223+
bufref_T bufref;
2224+
22232225
buf = curbuf;
2226+
set_bufref(&bufref, buf);
22242227
trigger_undo_ftplugin(buf, curwin);
22252228
// It's like this buffer is deleted. Watch out for autocommands that
22262229
// change curbuf! If that happens, allocate a new buffer anyway.
22272230
buf_freeall(buf, BFA_WIPE | BFA_DEL);
2228-
if (buf != curbuf) // autocommands deleted the buffer!
2229-
return NULL;
22302231
#ifdef FEAT_EVAL
22312232
if (aborting()) // autocmds may abort script processing
22322233
{
22332234
vim_free(ffname);
22342235
return NULL;
22352236
}
22362237
#endif
2238+
if (!bufref_valid(&bufref))
2239+
buf = NULL; // buf was deleted; allocate a new buffer
22372240
}
22382241
if (buf != curbuf || curbuf == NULL)
22392242
{

src/testdir/test_autocmd.vim

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5390,4 +5390,29 @@ func Test_eventignorewin_non_current()
53905390
%bw!
53915391
endfunc
53925392

5393+
func Test_reuse_curbuf_leak()
5394+
new bar
5395+
let s:bar_buf = bufnr()
5396+
augroup testing
5397+
autocmd!
5398+
autocmd BufDelete * ++once let s:triggered = 1 | execute s:bar_buf 'buffer'
5399+
augroup END
5400+
enew
5401+
let empty_buf = bufnr()
5402+
5403+
" Old curbuf should be reused, firing BufDelete. As BufDelete changes curbuf,
5404+
" reusing the buffer would fail and leak the ffname.
5405+
edit foo
5406+
call assert_equal(1, s:triggered)
5407+
" Wasn't reused because the buffer changed, but buffer "foo" is still created.
5408+
call assert_equal(1, bufexists(empty_buf))
5409+
call assert_notequal(empty_buf, bufnr())
5410+
call assert_equal('foo', bufname())
5411+
call assert_equal('bar', bufname(s:bar_buf))
5412+
5413+
unlet! s:bar_buf s:triggered
5414+
call CleanUpTestAuGroup()
5415+
%bw!
5416+
endfunc
5417+
53935418
" vim: shiftwidth=2 sts=2 expandtab

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,8 @@ static char *(features[]) =
704704

705705
static int included_patches[] =
706706
{ /* Add new patch number below this line */
707+
/**/
708+
1387,
707709
/**/
708710
1386,
709711
/**/

0 commit comments

Comments
 (0)