fix(swapfile): don't use uninitialized memory (#35813)

Also add a test for #35802.
This commit is contained in:
zeertzjq
2025-09-17 11:36:27 +08:00
committed by GitHub
parent 8ec562fe52
commit 63ece2b151
2 changed files with 44 additions and 7 deletions

View File

@@ -1403,8 +1403,8 @@ int recover_names(char *fname, bool do_list, list_T *ret_list, int nr, char **fn
StringBuilder msg = KV_INITIAL_VALUE; StringBuilder msg = KV_INITIAL_VALUE;
kv_resize(msg, IOSIZE); kv_resize(msg, IOSIZE);
swapfile_info(files[i], &msg); swapfile_info(files[i], &msg);
bool need_clear; bool need_clear = false;
msg_multiline(cstr_as_string(msg.items), 0, false, false, &need_clear); msg_multiline(cbuf_as_string(msg.items, msg.size), 0, false, false, &need_clear);
kv_destroy(msg); kv_destroy(msg);
} }
} else { } else {
@@ -3569,8 +3569,8 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_
// pretend screen didn't scroll, need redraw anyway // pretend screen didn't scroll, need redraw anyway
msg_reset_scroll(); msg_reset_scroll();
} else { } else {
bool need_clear; bool need_clear = false;
msg_multiline(cstr_as_string(msg.items), 0, false, false, &need_clear); msg_multiline(cbuf_as_string(msg.items, msg.size), 0, false, false, &need_clear);
} }
no_wait_return--; no_wait_return--;
kv_destroy(msg); kv_destroy(msg);

View File

@@ -9,6 +9,7 @@ local clear = n.clear
local command = n.command local command = n.command
local feed = n.feed local feed = n.feed
local fn = n.fn local fn = n.fn
local neq = t.neq
local nvim_prog = n.nvim_prog local nvim_prog = n.nvim_prog
local ok = t.ok local ok = t.ok
local rmdir = n.rmdir local rmdir = n.rmdir
@@ -51,7 +52,7 @@ describe("preserve and (R)ecover with custom 'directory'", function()
set swapfile fileformat=unix undolevels=-1 set swapfile fileformat=unix undolevels=-1
]] ]]
local nvim0 local nvim0 --- @type test.Session
before_each(function() before_each(function()
nvim0 = n.new_session(false) nvim0 = n.new_session(false)
set_session(nvim0) set_session(nvim0)
@@ -63,12 +64,13 @@ describe("preserve and (R)ecover with custom 'directory'", function()
rmdir(swapdir) rmdir(swapdir)
end) end)
--- @return string
local function setup_swapname() local function setup_swapname()
exec(init) exec(init)
command('edit! ' .. testfile) command('edit! ' .. testfile)
feed('isometext<esc>') feed('isometext<esc>')
exec('redir => g:swapname | silent swapname | redir END') exec('redir => g:swapname | silent swapname | redir END')
return eval('g:swapname') return eval('g:swapname'):match('[^\n]*$')
end end
local function test_recover(swappath1) local function test_recover(swappath1)
@@ -99,6 +101,7 @@ describe("preserve and (R)ecover with custom 'directory'", function()
it('with :preserve and SIGKILL', function() it('with :preserve and SIGKILL', function()
local swappath1 = setup_swapname() local swappath1 = setup_swapname()
command('preserve') command('preserve')
neq(nil, uv.fs_stat(swappath1))
eq(0, vim.uv.kill(eval('getpid()'), 'sigkill')) eq(0, vim.uv.kill(eval('getpid()'), 'sigkill'))
test_recover(swappath1) test_recover(swappath1)
end) end)
@@ -106,6 +109,7 @@ describe("preserve and (R)ecover with custom 'directory'", function()
it('closing stdio channel without :preserve #22096', function() it('closing stdio channel without :preserve #22096', function()
local swappath1 = setup_swapname() local swappath1 = setup_swapname()
nvim0:close() nvim0:close()
neq(nil, uv.fs_stat(swappath1))
test_recover(swappath1) test_recover(swappath1)
end) end)
@@ -124,13 +128,46 @@ describe("preserve and (R)ecover with custom 'directory'", function()
set_session(nvim0) set_session(nvim0)
command('call chanclose(&channel)') -- Kill the child process. command('call chanclose(&channel)') -- Kill the child process.
screen0:expect({ any = pesc('[Process exited 1]') }) -- Wait for the child process to stop. screen0:expect({ any = pesc('[Process exited 1]') }) -- Wait for the child process to stop.
neq(nil, uv.fs_stat(swappath1))
test_recover(swappath1) test_recover(swappath1)
end) end)
it('manual :recover with multiple swapfiles', function()
local swappath1 = setup_swapname()
eq('.swp', swappath1:match('%.[^.]+$'))
nvim0:close()
neq(nil, uv.fs_stat(swappath1))
local swappath2 = swappath1:gsub('%.swp$', '.swo')
eq(true, uv.fs_copyfile(swappath1, swappath2))
clear()
exec(init)
local screen = Screen.new(256, 40)
feed(':recover! ' .. testfile .. '<CR>')
screen:expect({
any = {
'\nSwap files found:',
'\n In directory ',
vim.pesc('\n1. '),
vim.pesc('\n2. '),
vim.pesc('\nEnter number of swap file to use (0 to quit): ^'),
},
none = vim.pesc('{18:^@}'),
})
feed('2<CR>')
screen:expect({
any = {
vim.pesc('\nRecovery completed.'),
vim.pesc('\n{6:Press ENTER or type command to continue}^'),
},
})
feed('<CR>')
expect('sometext')
end)
end) end)
describe('swapfile detection', function() describe('swapfile detection', function()
local swapdir = uv.cwd() .. '/Xtest_swapdialog_dir' local swapdir = uv.cwd() .. '/Xtest_swapdialog_dir'
local nvim0 local nvim0 --- @type test.Session
-- Put swapdir at the start of the 'directory' list. #1836 -- Put swapdir at the start of the 'directory' list. #1836
-- Note: `set swapfile` *must* go after `set directory`: otherwise it may -- Note: `set swapfile` *must* go after `set directory`: otherwise it may
-- attempt to create a swapfile in different directory. -- attempt to create a swapfile in different directory.