Skip to content

Commit

Permalink
console: make __autocomplete retrieval for cdata exception-safe
Browse files Browse the repository at this point in the history
Currently, the code which tries to retrieve the __autocomplete metamethod
for cdata (cf644ab) is not exception safe: an exception can be thrown from
the __index metamethod. In order to make it exception-safe and not
overcomplicate the code, let's add a Lua wrapper for table indexation, so
we can call it from C using `lua_pcall`.

Closes #9828

NO_CHANGELOG=<not released>
NO_DOC=<bugfix>
  • Loading branch information
CuriousGeorgiy authored and sergepetrenko committed Mar 28, 2024
1 parent c56998f commit ff7d8f0
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 1 deletion.
16 changes: 15 additions & 1 deletion src/box/lua/console.c
Expand Up @@ -288,6 +288,7 @@ static int saved_point = 0;

static int console_hide_prompt_ref = LUA_NOREF;
static int console_show_prompt_ref = LUA_NOREF;
static int gettable_ref = LUA_NOREF;

/**
* Don't attempt to hide/show prompt in certain readline states.
Expand Down Expand Up @@ -983,6 +984,13 @@ tarantool_lua_console_init(struct lua_State *L)
console_hide_prompt_ref = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushcfunction(L, lbox_console_show_prompt);
console_show_prompt_ref = luaL_ref(L, LUA_REGISTRYINDEX);

/*
* Compile a Lua wrapper for table indexation. For sanity, verify that
* it compiles successfully.
*/
VERIFY(luaT_dostring(L, "return function(t, k) return t[k] end") == 0);
gettable_ref = luaL_ref(L, LUA_REGISTRYINDEX);
}

/*
Expand Down Expand Up @@ -1116,8 +1124,14 @@ lua_rl_getcompletion(lua_State *L)
* metamethod instead of simply doing a raw lookup in the
* metatable.
*/
lua_rawgeti(L, LUA_REGISTRYINDEX, gettable_ref);
lua_pushvalue(L, -3);
lua_pushstring(L, "__autocomplete");
lua_gettable(L, -3);
if (lua_pcall(L, 2, 1, 0) != 0) {
/* pcall returns an error to the stack */
lua_pop(L, 1);
return 0;
}
}
if (lua_isfunction(L, -1)) {
lua_replace(L, -2);
Expand Down
6 changes: 6 additions & 0 deletions test/app-luatest/gh_6305_autocomplete_metamethod_test.lua
Expand Up @@ -58,6 +58,12 @@ g.test__autocomplete = function()
'table11.second',
'table11.auto',
})
-- __index function can throw an error - should be Ok
setmetatable(tab, {__index = function() error('test error') end})
t.assert_items_equals(tabcomplete('table11.'), {'table11.',
'table11.first',
'table11.second',
})
-- __autocomplete supercedes __index, no completions from the latter
setmetatable(tab, {__autocomplete = function() return {auto = true} end,
__index = {index = true}})
Expand Down

0 comments on commit ff7d8f0

Please sign in to comment.