fix(api): fail fast if has_lua_imp retval looks wrong #39866

This commit is contained in:
Justin M. Keyes
2026-05-20 11:52:22 -04:00
committed by GitHub
parent 584dfdb76d
commit 9f0ecad6d9
2 changed files with 17 additions and 2 deletions

View File

@@ -708,6 +708,9 @@ output:write('\n')
--- @type {binding: string, api:string}[]
local lua_c_functions = {}
--- Functions which use kRetMultiStack.
local lua_retstack = { nvim_buf_call = true, nvim_win_call = true }
--- Generates C code to bridge RPC API <=> Lua.
---
--- Inspect the result here:
@@ -844,6 +847,9 @@ local function process_function(fn)
end
write_shifted_output(' ENTER_LUA_ACTIVE_STATE(lstate);\n')
if fn.has_lua_imp and not lua_retstack[fn.name] then
write_shifted_output(' const int pretop = lua_gettop(lstate); (void)pretop;\n')
end
local free_at_exit_code = ''
for i = 1, #free_code do
local rev_i = #free_code - i + 1
@@ -882,8 +888,14 @@ exit_0:
local ret_type = real_type(fn.return_type)
local ret_mode = (ret_type == 'Object') and '&' or ''
if fn.has_lua_imp then
-- it is up to the function to push return values
write_shifted_output(' (void)ret;')
-- Most has_lua_imp functions are expected to produce a single retval (e.g.
-- nvim_buf_get_lines, but not kRetMultiStack callers such as nvim_buf_call). #39851
if not lua_retstack[fn.name] then
write_shifted_output(
' assert((ERROR_SET(&err) || lua_gettop(lstate) == pretop + 1) && "has_lua_imp function must push exactly one return value");\n'
)
end
write_shifted_output(' (void)ret;\n')
elseif ret_type:match('^KeyDict_') then
write_shifted_output(' nlua_push_keydict(lstate, &ret, %s_table);\n', return_type:sub(9))
else

View File

@@ -1808,6 +1808,9 @@ static int mode_ret(LuaRetMode mode)
Object nlua_call_ref_ctx(bool fast, LuaRef ref, const char *name, Array args, LuaRetMode mode,
Arena *arena, Error *err)
{
// Use active_lstate (set by ENTER_LUA_ACTIVE_STATE in gen_api_dispatch.lua) so callbacks run on
// the caller's Lua thread. This matters for coroutines: with global_lstate, return values pushed
// by kRetMultiStack would land on the main thread's stack, instead of coroutine stack.
lua_State *const lstate = active_lstate;
int top = lua_gettop(lstate);
nlua_pushref(lstate, ref);