mirror of
https://github.com/neovim/neovim.git
synced 2026-06-15 16:23:48 +00:00
backport: fix(api): leak preview callback LuaRef in nvim_create_user_command (#39377)
Problem:
Invalid `nvim_create_user_command` calls can leak the
`preview` callback reference after Neovim has taken ownership of it.
1. build with {a,l}san
2. run:
```sh
<path/to/nvim> --headless -u NONE --clean +'lua
for i = 1, 100 do
pcall(vim.api.nvim_create_user_command,
"some very epic stuff" .. i,
{}, -- NOTE: this is INVALID (not a function or string)
{ preview = function() end })
end
vim.cmd("qa!")
' +qa
```
3. see:
```
100 lua references were leaked!
```
Solution:
Clear `preview_luaref` in `err:`.
(cherry picked from commit 393f687503)
Co-authored-by: Barrett Ruth <62671086+barrettruth@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
4df16ecdb9
commit
e5d6d2e769
@@ -1279,7 +1279,8 @@ void create_user_command(uint64_t channel_id, String name, Union(String, LuaRef)
|
||||
if (uc_add_command(name.data, name.size, rep, argt, def, flags, context, compl_arg,
|
||||
compl_luaref, preview_luaref, addr_type_arg, luaref, force) != OK) {
|
||||
api_set_error(err, kErrorTypeException, "Failed to create user command");
|
||||
// Do not goto err, since uc_add_command now owns luaref, compl_luaref, and compl_arg
|
||||
// Do not goto err, since uc_add_command now owns luaref, compl_luaref, preview_luaref,
|
||||
// and compl_arg
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1288,6 +1289,7 @@ void create_user_command(uint64_t channel_id, String name, Union(String, LuaRef)
|
||||
err:
|
||||
NLUA_CLEAR_REF(luaref);
|
||||
NLUA_CLEAR_REF(compl_luaref);
|
||||
NLUA_CLEAR_REF(preview_luaref);
|
||||
xfree(compl_arg);
|
||||
}
|
||||
/// Gets a map of global (non-buffer-local) Ex commands.
|
||||
|
||||
@@ -274,6 +274,25 @@ describe('nvim_create_user_command', function()
|
||||
eq(42, api.nvim_eval('g:command_fired'))
|
||||
end)
|
||||
|
||||
it('does not leak `preview` LuaRef on invalid `cmd`', function()
|
||||
local released = exec_lua(function()
|
||||
local weak = setmetatable({}, { __mode = 'v' })
|
||||
for i = 1, 10 do
|
||||
local cb = function() end
|
||||
weak[i] = cb
|
||||
pcall(vim.api.nvim_create_user_command, 'Bogus' .. i, {}, { preview = cb })
|
||||
end
|
||||
collectgarbage('collect')
|
||||
collectgarbage('collect')
|
||||
local n = 0
|
||||
for _ in pairs(weak) do
|
||||
n = n + 1
|
||||
end
|
||||
return n
|
||||
end)
|
||||
eq(0, released)
|
||||
end)
|
||||
|
||||
it('works with Lua functions', function()
|
||||
exec_lua [[
|
||||
result = {}
|
||||
|
||||
Reference in New Issue
Block a user