mirror of
https://github.com/vim/vim
synced 2025-07-16 09:12:00 +00:00
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>
This commit is contained in:
committed by
Christian Brabandt
parent
c952fd1b24
commit
0077282c82
@ -2220,13 +2220,14 @@ buflist_new(
|
|||||||
buf = NULL;
|
buf = NULL;
|
||||||
if ((flags & BLN_CURBUF) && curbuf_reusable())
|
if ((flags & BLN_CURBUF) && curbuf_reusable())
|
||||||
{
|
{
|
||||||
|
bufref_T bufref;
|
||||||
|
|
||||||
buf = curbuf;
|
buf = curbuf;
|
||||||
|
set_bufref(&bufref, buf);
|
||||||
trigger_undo_ftplugin(buf, curwin);
|
trigger_undo_ftplugin(buf, curwin);
|
||||||
// It's like this buffer is deleted. Watch out for autocommands that
|
// It's like this buffer is deleted. Watch out for autocommands that
|
||||||
// change curbuf! If that happens, allocate a new buffer anyway.
|
// change curbuf! If that happens, allocate a new buffer anyway.
|
||||||
buf_freeall(buf, BFA_WIPE | BFA_DEL);
|
buf_freeall(buf, BFA_WIPE | BFA_DEL);
|
||||||
if (buf != curbuf) // autocommands deleted the buffer!
|
|
||||||
return NULL;
|
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
if (aborting()) // autocmds may abort script processing
|
if (aborting()) // autocmds may abort script processing
|
||||||
{
|
{
|
||||||
@ -2234,6 +2235,8 @@ buflist_new(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (!bufref_valid(&bufref))
|
||||||
|
buf = NULL; // buf was deleted; allocate a new buffer
|
||||||
}
|
}
|
||||||
if (buf != curbuf || curbuf == NULL)
|
if (buf != curbuf || curbuf == NULL)
|
||||||
{
|
{
|
||||||
|
@ -5390,4 +5390,29 @@ func Test_eventignorewin_non_current()
|
|||||||
%bw!
|
%bw!
|
||||||
endfunc
|
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
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1387,
|
||||||
/**/
|
/**/
|
||||||
1386,
|
1386,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user