From 4365a45d681b4e71e3c39148489bb8eae538ccf7 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Tue, 6 May 2025 15:54:05 -0300 Subject: Checks for read-only globals --- lcode.c | 3 ++- lparser.c | 24 ++++++++++++++++++------ lparser.h | 5 +++-- testes/locals.lua | 10 ++++++++++ 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/lcode.c b/lcode.c index e8b9bb5d..8f658500 100644 --- a/lcode.c +++ b/lcode.c @@ -1315,8 +1315,8 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { luaK_exp2anyreg(fs, t); /* put it in a register */ if (t->k == VUPVAL) { lu_byte temp = cast_byte(t->u.info); /* upvalue index */ - lua_assert(isKstr(fs, k)); t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */ + lua_assert(isKstr(fs, k)); t->u.ind.idx = cast(short, k->u.info); /* literal short string */ t->k = VINDEXUP; } @@ -1336,6 +1336,7 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { t->k = VINDEXED; } } + t->u.ind.vidx = -1; /* by default, not a declared global */ } diff --git a/lparser.c b/lparser.c index 1c5fdca6..61ce0908 100644 --- a/lparser.c +++ b/lparser.c @@ -200,7 +200,7 @@ static int new_varkind (LexState *ls, TString *name, lu_byte kind) { luaY_checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, MAXVARS, "local variables"); luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, - dyd->actvar.size, Vardesc, SHRT_MAX, "local variables"); + dyd->actvar.size, Vardesc, SHRT_MAX, "variable declarationss"); var = &dyd->actvar.arr[dyd->actvar.n++]; var->vd.kind = kind; /* default */ var->vd.name = name; @@ -276,7 +276,7 @@ static LocVar *localdebuginfo (FuncState *fs, int vidx) { static void init_var (FuncState *fs, expdesc *e, int vidx) { e->f = e->t = NO_JUMP; e->k = VLOCAL; - e->u.var.vidx = cast(unsigned short, vidx); + e->u.var.vidx = cast(short, vidx); e->u.var.ridx = getlocalvardesc(fs, vidx)->vd.ridx; } @@ -304,8 +304,16 @@ static void check_readonly (LexState *ls, expdesc *e) { varname = up->name; break; } + case VINDEXUP: case VINDEXSTR: case VINDEXED: { + int vidx = e->u.ind.vidx; + /* is it a read-only declared global? */ + if (vidx != -1 && ls->dyd->actvar.arr[vidx].vd.kind == GDKCONST) + varname = ls->dyd->actvar.arr[vidx].vd.name; + break; + } default: - return; /* other cases cannot be read-only */ + lua_assert(e->k == VINDEXI); /* this one doesn't need any check */ + return; /* integer index cannot be read-only */ } if (varname) luaK_semerror(ls, "attempt to assign to const variable '%s'", @@ -391,7 +399,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) { /* -** Look for an active local variable with the name 'n' in the +** Look for an active variable with the name 'n' in the ** function 'fs'. If found, initialize 'var' with it and return ** its expression kind; otherwise return -1. */ @@ -403,7 +411,7 @@ static int searchvar (FuncState *fs, TString *n, expdesc *var) { if (vd->vd.kind == RDKCTC) /* compile-time constant? */ init_exp(var, VCONST, fs->firstlocal + i); else if (vd->vd.kind == GDKREG || vd->vd.kind == GDKCONST) - init_exp(var, VGLOBAL, i); + init_exp(var, VGLOBAL, fs->firstlocal + i); else /* local variable */ init_var(fs, var, i); return cast_int(var->k); @@ -475,8 +483,11 @@ static void singlevar (LexState *ls, expdesc *var) { singlevaraux(fs, varname, var, 1); if (var->k == VGLOBAL) { /* global name? */ expdesc key; + int info = var->u.info; + lua_assert(info == -1 || + eqstr(ls->dyd->actvar.arr[info].vd.name, varname)); /* global by default in the scope of a global declaration? */ - if (var->u.info == -1 && fs->bl->globdec) + if (info == -1 && fs->bl->globdec) luaK_semerror(ls, "variable '%s' not declared", getstr(varname)); singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ if (var->k == VGLOBAL) @@ -485,6 +496,7 @@ static void singlevar (LexState *ls, expdesc *var) { luaK_exp2anyregup(fs, var); /* but could be a constant */ codestring(&key, varname); /* key is variable name */ luaK_indexed(fs, var, &key); /* env[varname] */ + var->u.ind.vidx = cast(short, info); /* mark it as a declared global */ } } diff --git a/lparser.h b/lparser.h index 3cd0ba77..274fb1c4 100644 --- a/lparser.h +++ b/lparser.h @@ -77,11 +77,12 @@ typedef struct expdesc { int info; /* for generic use */ struct { /* for indexed variables */ short idx; /* index (R or "long" K) */ + short vidx; /* index in 'actvar.arr' or -1 if not a declared global */ lu_byte t; /* table (register or upvalue) */ } ind; struct { /* for local variables */ lu_byte ridx; /* register holding the variable */ - unsigned short vidx; /* compiler index (in 'actvar.arr') */ + short vidx; /* index in 'actvar.arr' */ } var; } u; int t; /* patch list of 'exit when true' */ @@ -101,7 +102,7 @@ typedef struct expdesc { #define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE) -/* description of an active local variable */ +/* description of an active variable */ typedef union Vardesc { struct { TValuefields; /* constant value (if it is a compile-time constant) */ diff --git a/testes/locals.lua b/testes/locals.lua index eeeb4338..421595bb 100644 --- a/testes/locals.lua +++ b/testes/locals.lua @@ -178,6 +178,8 @@ A = nil do -- constants + global assert, load, string, X + X = 1 -- not a constant local a, b, c = 10, 20, 30 b = a + c + b -- 'b' is not constant assert(a == 10 and b == 60 and c == 30) @@ -191,6 +193,9 @@ do -- constants checkro("z", "local x , y, z = 10, 20, 30; y = 10; z = 11") checkro("foo", "local foo = 10; function foo() end") checkro("foo", "local foo = {}; function foo() end") + checkro("foo", "global foo ; function foo() end") + checkro("XX", "global XX ; XX = 10") + checkro("XX", "local _ENV; global XX ; XX = 10") checkro("z", [[ local a, z , b = 10; @@ -201,6 +206,11 @@ do -- constants local a, var1 = 10; function foo() a = 20; z = function () var1 = 12; end end ]]) + + checkro("var1", [[ + global a, var1 , z; + local function foo() a = 20; z = function () var1 = 12; end end + ]]) end -- cgit v1.2.3-55-g6feb