From 80f3ecc44f1b137cde86c7a7821209a2d88cbdf1 Mon Sep 17 00:00:00 2001 From: Roberto I Date: Mon, 12 Oct 2026 16:12:40 -0300 Subject: [PATCH] Avoid underflows in 'luaF_getlocalname' A call like 'debug.getlocal(test, -2147483648)' could decrement -2147483648, causing an underflow. (As this happens in a debug function, the fix was not strictly necessary, but it has no cost in the generated code.) --- ldebug.c | 6 +++--- lfunc.c | 2 +- lfunc.h | 4 ++-- ltests.c | 2 +- testes/db.lua | 1 + 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ldebug.c b/ldebug.c index 61c52749..58d8731e 100644 --- a/ldebug.c +++ b/ldebug.c @@ -202,7 +202,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) { if (n < 0) /* access to vararg values? */ return findvararg(ci, n, pos); else - name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); + name = luaF_getlocalname(ci_func(ci)->p, cast_uint(n), currentpc(ci)); } if (name == NULL) { /* no 'standard' name? */ StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p; @@ -226,7 +226,7 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */ name = NULL; else /* consider live variables at function start (parameters) */ - name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0); + name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, cast_uint(n), 0); } else { /* active function; get information through 'ar' */ StkId pos = NULL; /* to avoid warnings */ @@ -505,7 +505,7 @@ static const char *kname (const Proto *p, int index, const char **name) { static const char *basicgetobjname (const Proto *p, int *ppc, int reg, const char **name) { int pc = *ppc; - *name = luaF_getlocalname(p, reg + 1, pc); + *name = luaF_getlocalname(p, cast_uint(reg + 1), pc); if (*name) /* is a local? */ return strlocal; /* else try symbolic execution */ diff --git a/lfunc.c b/lfunc.c index b6fd9ceb..84a5b186 100644 --- a/lfunc.c +++ b/lfunc.c @@ -300,7 +300,7 @@ void luaF_freeproto (lua_State *L, Proto *f) { ** Look for n-th local variable at line 'line' in function 'func'. ** Returns NULL if not found. */ -const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { +const char *luaF_getlocalname (const Proto *f, unsigned local_number, int pc) { int i; for (i = 0; isizelocvars && f->locvars[i].startpc <= pc; i++) { if (pc < f->locvars[i].endpc) { /* is variable active? */ diff --git a/lfunc.h b/lfunc.h index d6aad3a6..e53a4974 100644 --- a/lfunc.h +++ b/lfunc.h @@ -58,8 +58,8 @@ LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, TStatus status, int yy); LUAI_FUNC void luaF_unlinkupval (UpVal *uv); LUAI_FUNC lu_mem luaF_protosize (Proto *p); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); -LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, - int pc); +LUAI_FUNC const char *luaF_getlocalname (const Proto *func, + unsigned local_number, int pc); #endif diff --git a/ltests.c b/ltests.c index 2bf5545a..6bfd55f9 100644 --- a/ltests.c +++ b/ltests.c @@ -853,7 +853,7 @@ static int listlocals (lua_State *L) { luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, "Lua function expected"); p = getproto(obj_at(L, 1)); - while ((name = luaF_getlocalname(p, ++i, pc)) != NULL) + while ((name = luaF_getlocalname(p, cast_uint(++i), pc)) != NULL) lua_pushstring(L, name); return i-1; } diff --git a/testes/db.lua b/testes/db.lua index e15a5be6..e754c06d 100644 --- a/testes/db.lua +++ b/testes/db.lua @@ -258,6 +258,7 @@ print'+' -- invalid levels in [gs]etlocal assert(not pcall(debug.getlocal, 20, 1)) assert(not pcall(debug.setlocal, -1, 1, 10)) +assert(not debug.getlocal(test, -2147483648)) -- parameter names