From d4eff00234dc55dac4cb86b6187f5607c1254f9b Mon Sep 17 00:00:00 2001 From: Roberto I Date: Wed, 29 Oct 2025 13:14:48 -0300 Subject: Fixed initialization of global variables When calling 'luaK_storevar', the 'expdesc' for the variable must be created before the one for the expression, to satisfy the assumptions for register allocation. So, in a statement like 'global a = exp', where 'a' is actually '_ENV.a', this variable must be handled before the initializing expression 'exp'. --- lcode.c | 2 +- lparser.c | 41 +++++++++++++++++++++++++++++------------ testes/goto.lua | 22 ++++++++++++++++++++++ 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/lcode.c b/lcode.c index 429d4f80..7c63abb2 100644 --- a/lcode.c +++ b/lcode.c @@ -1242,7 +1242,7 @@ static void codenot (FuncState *fs, expdesc *e) { ** Check whether expression 'e' is a short literal string */ static int isKstr (FuncState *fs, expdesc *e) { - return (e->k == VK && !hasjumps(e) && e->u.info <= MAXARG_B && + return (e->k == VK && !hasjumps(e) && e->u.info <= MAXINDEXRK && ttisshrstring(&fs->f->k[e->u.info])); } diff --git a/lparser.c b/lparser.c index dc646fea..e3538c16 100644 --- a/lparser.c +++ b/lparser.c @@ -1875,6 +1875,33 @@ static lu_byte getglobalattribute (LexState *ls, lu_byte df) { } +/* +** Recursively traverse list of globals to be initalized. When +** going, generate table description for the global. In the end, +** after all indices have been generated, read list of initializing +** expressions. When returning, generate the assignment of the value on +** the stack to the corresponding table description. 'n' is the variable +** being handled, range [0, nvars - 1]. +*/ +static void initglobal (LexState *ls, int nvars, int firstidx, int n) { + if (n == nvars) { /* traversed all variables? */ + expdesc e; + int nexps = explist(ls, &e); /* read list of expressions */ + adjust_assign(ls, nvars, nexps, &e); + } + else { /* handle variable 'n' */ + FuncState *fs = ls->fs; + expdesc var; + TString *varname = getlocalvardesc(fs, firstidx + n)->vd.name; + buildglobal(ls, varname, &var); /* create global variable in 'var' */ + enterlevel(ls); /* control recursion depth */ + initglobal(ls, nvars, firstidx, n + 1); + leavelevel(ls); + storevartop(fs, &var); + } +} + + static void globalnames (LexState *ls, lu_byte defkind) { FuncState *fs = ls->fs; int nvars = 0; @@ -1885,18 +1912,8 @@ static void globalnames (LexState *ls, lu_byte defkind) { lastidx = new_varkind(ls, vname, kind); nvars++; } while (testnext(ls, ',')); - if (testnext(ls, '=')) { /* initialization? */ - expdesc e; - int i; - int nexps = explist(ls, &e); /* read list of expressions */ - adjust_assign(ls, nvars, nexps, &e); - for (i = 0; i < nvars; i++) { /* for each variable */ - expdesc var; - TString *varname = getlocalvardesc(fs, lastidx - i)->vd.name; - buildglobal(ls, varname, &var); /* create global variable in 'var' */ - storevartop(fs, &var); - } - } + if (testnext(ls, '=')) /* initialization? */ + initglobal(ls, nvars, lastidx - nvars + 1, 0); fs->nactvar = cast_short(fs->nactvar + nvars); /* activate declaration */ } diff --git a/testes/goto.lua b/testes/goto.lua index 3310314d..a692a623 100644 --- a/testes/goto.lua +++ b/testes/goto.lua @@ -432,5 +432,27 @@ do print "testing initialization in global declarations" _ENV.a, _ENV.b, _ENV.c, _ENV.d = nil -- erase these globals end +do + global table, string + -- global initialization when names don't fit in K + + -- to fill constant table + local code = {} + for i = 1, 300 do code[i] = "'" .. i .. "'" end + code = table.concat(code, ",") + code = string.format([[ + return function (_ENV) + local dummy = {%s} -- fill initial positions in constant table, + -- so that initialization must use registers for global names + global a, b, c = 10, 20, 30 + end]], code) + + local fun = assert(load(code))() + + local env = {} + fun(env) + assert(env.a == 10 and env.b == 20 and env.c == 30) +end + print'OK' -- cgit v1.2.3-55-g6feb