From bdc85357aa41a9610498232c2cffe7aa191e5cf6 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Tue, 4 Jun 2024 17:27:13 -0300 Subject: [PATCH] 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. --- ldebug.c | 36 +++++++++++++++++++----------------- manual/manual.of | 12 ++++++------ testes/db.lua | 9 +++++++++ 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/ldebug.c b/ldebug.c index daa979af..e199decf 100644 --- a/ldebug.c +++ b/ldebug.c @@ -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, @@ -255,7 +255,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { static void funcinfo (lua_Debug *ar, Closure *cl) { - if (noLuaClosure(cl)) { + if (!LuaClosure(cl)) { ar->source = "=[C]"; ar->srclen = LL("=[C]"); 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) { - if (noLuaClosure(f)) { + if (!LuaClosure(f)) { setnilvalue(s2v(L->top.p)); api_incr_top(L); } else { - int i; - TValue v; const Proto *p = f->l.p; int currentline = p->linedefined; Table *t = luaH_new(L); /* new table to store active lines */ sethvalue2s(L, L->top.p, t); /* push it on stack */ api_incr_top(L); - setbtvalue(&v); /* boolean 'true' to be the value of all indices */ - if (!(p->flag & PF_ISVARARG)) /* regular function? */ - i = 0; /* consider all instructions */ - else { /* vararg function */ - lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); - currentline = nextline(p, currentline, 0); - i = 1; /* skip first instruction (OP_VARARGPREP) */ - } - 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 */ + if (p->lineinfo != NULL) { /* proto with debug information? */ + int i; + TValue v; + setbtvalue(&v); /* boolean 'true' to be the value of all indices */ + if (!(p->flag & PF_ISVARARG)) /* regular function? */ + i = 0; /* consider all instructions */ + else { /* vararg function */ + lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); + currentline = nextline(p, currentline, 0); + i = 1; /* skip first instruction (OP_VARARGPREP) */ + } + 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': { ar->nups = (f == NULL) ? 0 : f->c.nupvalues; - if (noLuaClosure(f)) { + if (!LuaClosure(f)) { ar->isvararg = 1; ar->nparams = 0; } diff --git a/manual/manual.of b/manual/manual.of index 337731fe..4fbdbf31 100644 --- a/manual/manual.of +++ b/manual/manual.of @@ -8942,13 +8942,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. The default for @id{what} is to get all information available, 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. -If present, -the option @Char{L} -adds a field named @id{activelines} with the table of -valid lines. +The option @Char{L} adds a field named @id{activelines} +with the table of valid lines, +provided the function is a Lua function. +If the function has no debug information, +the table is empty. For instance, the expression @T{debug.getinfo(1,"n").name} returns a name for the current function, diff --git a/testes/db.lua b/testes/db.lua index d3758c41..49ff8e3e 100644 --- a/testes/db.lua +++ b/testes/db.lua @@ -49,6 +49,15 @@ do 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 local a = "function f () end" local function dostring (s, x) return load(s, x)() end