vim-patch:8.2.1905: the wininfo list may contain stale entries (#14884)

Problem:    The wininfo list may contain stale entries.
Solution:   When closing a window remove any other entry where the window
            pointer is NULL.
4882d98339
This commit is contained in:
Daniel Steinberg 2021-06-30 21:24:50 -04:00 committed by GitHub
parent d83bc835b6
commit 8bd6990084
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 68 additions and 7 deletions

View File

@ -840,11 +840,7 @@ static void clear_wininfo(buf_T *buf)
while (buf->b_wininfo != NULL) { while (buf->b_wininfo != NULL) {
wip = buf->b_wininfo; wip = buf->b_wininfo;
buf->b_wininfo = wip->wi_next; buf->b_wininfo = wip->wi_next;
if (wip->wi_optset) { free_wininfo(wip, buf);
clear_winopt(&wip->wi_opt);
deleteFoldRecurse(buf, &wip->wi_folds);
}
xfree(wip);
} }
} }

View File

@ -4597,6 +4597,18 @@ static win_T *win_alloc(win_T *after, int hidden)
} }
// Free one wininfo_T.
void
free_wininfo(wininfo_T *wip, buf_T *bp)
{
if (wip->wi_optset) {
clear_winopt(&wip->wi_opt);
deleteFoldRecurse(bp, &wip->wi_folds);
}
xfree(wip);
}
/* /*
* Remove window 'wp' from the window list and free the structure. * Remove window 'wp' from the window list and free the structure.
*/ */
@ -4647,10 +4659,31 @@ win_free (
/* Remove the window from the b_wininfo lists, it may happen that the /* Remove the window from the b_wininfo lists, it may happen that the
* freed memory is re-used for another window. */ * freed memory is re-used for another window. */
FOR_ALL_BUFFERS(buf) { FOR_ALL_BUFFERS(buf) {
for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next) for (wip = buf->b_wininfo; wip != NULL; wip = wip->wi_next) {
if (wip->wi_win == wp) if (wip->wi_win == wp) {
wininfo_T *wip2;
// If there already is an entry with "wi_win" set to NULL it
// must be removed, it would never be used.
for (wip2 = buf->b_wininfo; wip2 != NULL; wip2 = wip2->wi_next) {
if (wip2->wi_win == NULL) {
if (wip2->wi_next != NULL) {
wip2->wi_next->wi_prev = wip2->wi_prev;
}
if (wip2->wi_prev == NULL) {
buf->b_wininfo = wip2->wi_next;
} else {
wip2->wi_prev->wi_next = wip2->wi_next;
}
free_wininfo(wip2, buf);
break;
}
}
wip->wi_win = NULL; wip->wi_win = NULL;
} }
}
}
clear_matches(wp); clear_matches(wp);

View File

@ -166,4 +166,36 @@ describe('memory usage', function()
check_result({before=before, after=after, last=last}, check_result({before=before, after=after, last=last},
pcall(ok, last.last < upper)) pcall(ok, last.last < upper))
end) end)
it('releases memory when closing windows when folds exist', function()
local pid = eval('getpid()')
source([[
new
" Insert lines
call nvim_buf_set_lines(0, 0, 0, v:false, repeat([''], 999))
" Create folds
normal! gg
for _ in range(500)
normal! zfjj
endfor
]])
poke_eventloop()
local before = monitor_memory_usage(pid)
source([[
" Split and close window multiple times
for _ in range(1000)
split
close
endfor
]])
poke_eventloop()
local after = monitor_memory_usage(pid)
source('bwipe!')
poke_eventloop()
-- Allow for an increase of 5% in memory usage, which accommodates minor fluctuation,
-- but is small enough that if memory were not released (prior to PR #14884), the test
-- would fail.
local upper = before.last * 1.05
check_result({before=before, after=after}, pcall(ok, after.last <= upper))
end)
end) end)