Bug: Active-lines for stripped vararg functions

Lua seg. faults when asked to create the 'activelines' table for a
vararg function with no debug information.
This commit is contained in:
Roberto Ierusalimschy 2024-05-13 13:10:35 -03:00
parent de794a6527
commit dfbde4c7d5
3 changed files with 34 additions and 23 deletions

View File

@ -31,7 +31,7 @@
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) #define LuaClosure(f) ((f) != NULL && (f)->c.tt == LUA_VLCL)
static const char *funcnamefromcall (lua_State *L, CallInfo *ci, static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
@ -254,7 +254,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
static void funcinfo (lua_Debug *ar, Closure *cl) { static void funcinfo (lua_Debug *ar, Closure *cl) {
if (noLuaClosure(cl)) { if (!LuaClosure(cl)) {
ar->source = "=[C]"; ar->source = "=[C]";
ar->srclen = LL("=[C]"); ar->srclen = LL("=[C]");
ar->linedefined = -1; ar->linedefined = -1;
@ -288,29 +288,31 @@ static int nextline (const Proto *p, int currentline, int pc) {
static void collectvalidlines (lua_State *L, Closure *f) { static void collectvalidlines (lua_State *L, Closure *f) {
if (noLuaClosure(f)) { if (!LuaClosure(f)) {
setnilvalue(s2v(L->top.p)); setnilvalue(s2v(L->top.p));
api_incr_top(L); api_incr_top(L);
} }
else { else {
int i;
TValue v;
const Proto *p = f->l.p; const Proto *p = f->l.p;
int currentline = p->linedefined; int currentline = p->linedefined;
Table *t = luaH_new(L); /* new table to store active lines */ Table *t = luaH_new(L); /* new table to store active lines */
sethvalue2s(L, L->top.p, t); /* push it on stack */ sethvalue2s(L, L->top.p, t); /* push it on stack */
api_incr_top(L); api_incr_top(L);
setbtvalue(&v); /* boolean 'true' to be the value of all indices */ if (p->lineinfo != NULL) { /* proto with debug information? */
if (!p->is_vararg) /* regular function? */ int i;
i = 0; /* consider all instructions */ TValue v;
else { /* vararg function */ setbtvalue(&v); /* boolean 'true' to be the value of all indices */
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); if (!p->is_vararg) /* regular function? */
currentline = nextline(p, currentline, 0); i = 0; /* consider all instructions */
i = 1; /* skip first instruction (OP_VARARGPREP) */ else { /* vararg function */
} lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
for (; i < p->sizelineinfo; i++) { /* for each instruction */ currentline = nextline(p, currentline, 0);
currentline = nextline(p, currentline, i); /* get its line */ i = 1; /* skip first instruction (OP_VARARGPREP) */
luaH_setint(L, t, currentline, &v); /* table[line] = true */ }
for (; i < p->sizelineinfo; i++) { /* for each instruction */
currentline = nextline(p, currentline, i); /* get its line */
luaH_setint(L, t, currentline, &v); /* table[line] = true */
}
} }
} }
} }
@ -339,7 +341,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
} }
case 'u': { case 'u': {
ar->nups = (f == NULL) ? 0 : f->c.nupvalues; ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
if (noLuaClosure(f)) { if (!LuaClosure(f)) {
ar->isvararg = 1; ar->isvararg = 1;
ar->nparams = 0; ar->nparams = 0;
} }

View File

@ -8773,13 +8773,13 @@ The returned table can contain all the fields returned by @Lid{lua_getinfo},
with the string @id{what} describing which fields to fill in. with the string @id{what} describing which fields to fill in.
The default for @id{what} is to get all information available, The default for @id{what} is to get all information available,
except the table of valid lines. except the table of valid lines.
If present, The option @Char{f}
the option @Char{f}
adds a field named @id{func} with the function itself. adds a field named @id{func} with the function itself.
If present, The option @Char{L} adds a field named @id{activelines}
the option @Char{L} with the table of valid lines,
adds a field named @id{activelines} with the table of provided the function is a Lua function.
valid lines. If the function has no debug information,
the table is empty.
For instance, the expression @T{debug.getinfo(1,"n").name} returns For instance, the expression @T{debug.getinfo(1,"n").name} returns
a name for the current function, a name for the current function,

View File

@ -49,6 +49,15 @@ do
end end
-- bug in 5.4.4-5.4.6: activelines in vararg functions
-- without debug information
do
local func = load(string.dump(load("print(10)"), true))
local actl = debug.getinfo(func, "L").activelines
assert(#actl == 0) -- no line info
end
-- test file and string names truncation -- test file and string names truncation
local a = "function f () end" local a = "function f () end"
local function dostring (s, x) return load(s, x)() end local function dostring (s, x) return load(s, x)() end