'table.tunpack' using 'aux_getn' like the others

'table.tunpack' was not checking its first argument, which could
result in error messages generated inside the API, without location
information.
This commit is contained in:
Roberto I
2026-03-09 16:24:49 -03:00
parent 36d5d2b284
commit 377cbea61b
2 changed files with 20 additions and 4 deletions

View File

@@ -42,15 +42,17 @@ static int checkfield (lua_State *L, const char *key, int n) {
/* /*
** Check that 'arg' either is a table or can behave like one (that is, ** Check that 'arg' either is a table or can behave like one (that is,
** has a metatable with the required metamethods) ** has a metatable with the required metamethods).
*/ */
static void checktab (lua_State *L, int arg, int what) { static void checktab (lua_State *L, int arg, int what) {
if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ int tp = lua_type(L, arg);
if (tp != LUA_TTABLE) { /* is it not a table? */
int n = 1; /* number of elements to pop */ int n = 1; /* number of elements to pop */
if (lua_getmetatable(L, arg) && /* must have metatable */ if (lua_getmetatable(L, arg) && /* must have metatable */
(!(what & TAB_R) || checkfield(L, "__index", ++n)) && (!(what & TAB_R) || checkfield(L, "__index", ++n)) &&
(!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) &&
(!(what & TAB_L) || checkfield(L, "__len", ++n))) { (!(what & TAB_L) || /* strings don't need '__len' to have a length */
tp == LUA_TSTRING || checkfield(L, "__len", ++n))) {
lua_pop(L, n); /* pop metatable and tested metamethods */ lua_pop(L, n); /* pop metatable and tested metamethods */
} }
else else
@@ -204,8 +206,9 @@ static int tpack (lua_State *L) {
static int tunpack (lua_State *L) { static int tunpack (lua_State *L) {
lua_Unsigned n; lua_Unsigned n;
lua_Integer len = aux_getn(L, 1, TAB_R);
lua_Integer i = luaL_optinteger(L, 2, 1); lua_Integer i = luaL_optinteger(L, 2, 1);
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, len);
if (i > e) return 0; /* empty range */ if (i > e) return 0; /* empty range */
n = l_castS2U(e) - l_castS2U(i); /* number of elements minus 1 */ n = l_castS2U(e) - l_castS2U(i); /* number of elements minus 1 */
if (l_unlikely(n >= (unsigned int)INT_MAX || if (l_unlikely(n >= (unsigned int)INT_MAX ||

View File

@@ -72,6 +72,19 @@ assert(a==1 and x==nil)
a,x = unpack({1,2}, 1, 1) a,x = unpack({1,2}, 1, 1)
assert(a==1 and x==nil) assert(a==1 and x==nil)
do -- unpack with non-tables
local debug = require"debug"
local oldmt = debug.getmetatable(0)
local str = "hello"
debug.setmetatable(0,
{ __len = function () return #str end,
__index = function (_, i) return string.sub(str, i, i) end})
assert(table.concat({table.unpack(0)}) == str)
debug.setmetatable(0, oldmt) -- restore original metatable for numbers
end
do do
local maxi = (1 << 31) - 1 -- maximum value for an int (usually) local maxi = (1 << 31) - 1 -- maximum value for an int (usually)
local mini = -(1 << 31) -- minimum value for an int (usually) local mini = -(1 << 31) -- minimum value for an int (usually)