aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2025-05-06 15:54:05 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2025-05-06 15:54:05 -0300
commit4365a45d681b4e71e3c39148489bb8eae538ccf7 (patch)
treeea22f0836f252edd7bc7279772158f2b7e549b1e
parentbe8120906304a8658fab998587b969e0e42f5650 (diff)
downloadlua-4365a45d681b4e71e3c39148489bb8eae538ccf7.tar.gz
lua-4365a45d681b4e71e3c39148489bb8eae538ccf7.tar.bz2
lua-4365a45d681b4e71e3c39148489bb8eae538ccf7.zip
Checks for read-only globals
-rw-r--r--lcode.c3
-rw-r--r--lparser.c24
-rw-r--r--lparser.h5
-rw-r--r--testes/locals.lua10
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) {
1315 luaK_exp2anyreg(fs, t); /* put it in a register */ 1315 luaK_exp2anyreg(fs, t); /* put it in a register */
1316 if (t->k == VUPVAL) { 1316 if (t->k == VUPVAL) {
1317 lu_byte temp = cast_byte(t->u.info); /* upvalue index */ 1317 lu_byte temp = cast_byte(t->u.info); /* upvalue index */
1318 lua_assert(isKstr(fs, k));
1319 t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */ 1318 t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */
1319 lua_assert(isKstr(fs, k));
1320 t->u.ind.idx = cast(short, k->u.info); /* literal short string */ 1320 t->u.ind.idx = cast(short, k->u.info); /* literal short string */
1321 t->k = VINDEXUP; 1321 t->k = VINDEXUP;
1322 } 1322 }
@@ -1336,6 +1336,7 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
1336 t->k = VINDEXED; 1336 t->k = VINDEXED;
1337 } 1337 }
1338 } 1338 }
1339 t->u.ind.vidx = -1; /* by default, not a declared global */
1339} 1340}
1340 1341
1341 1342
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) {
200 luaY_checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, 200 luaY_checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
201 MAXVARS, "local variables"); 201 MAXVARS, "local variables");
202 luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, 202 luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1,
203 dyd->actvar.size, Vardesc, SHRT_MAX, "local variables"); 203 dyd->actvar.size, Vardesc, SHRT_MAX, "variable declarationss");
204 var = &dyd->actvar.arr[dyd->actvar.n++]; 204 var = &dyd->actvar.arr[dyd->actvar.n++];
205 var->vd.kind = kind; /* default */ 205 var->vd.kind = kind; /* default */
206 var->vd.name = name; 206 var->vd.name = name;
@@ -276,7 +276,7 @@ static LocVar *localdebuginfo (FuncState *fs, int vidx) {
276static void init_var (FuncState *fs, expdesc *e, int vidx) { 276static void init_var (FuncState *fs, expdesc *e, int vidx) {
277 e->f = e->t = NO_JUMP; 277 e->f = e->t = NO_JUMP;
278 e->k = VLOCAL; 278 e->k = VLOCAL;
279 e->u.var.vidx = cast(unsigned short, vidx); 279 e->u.var.vidx = cast(short, vidx);
280 e->u.var.ridx = getlocalvardesc(fs, vidx)->vd.ridx; 280 e->u.var.ridx = getlocalvardesc(fs, vidx)->vd.ridx;
281} 281}
282 282
@@ -304,8 +304,16 @@ static void check_readonly (LexState *ls, expdesc *e) {
304 varname = up->name; 304 varname = up->name;
305 break; 305 break;
306 } 306 }
307 case VINDEXUP: case VINDEXSTR: case VINDEXED: {
308 int vidx = e->u.ind.vidx;
309 /* is it a read-only declared global? */
310 if (vidx != -1 && ls->dyd->actvar.arr[vidx].vd.kind == GDKCONST)
311 varname = ls->dyd->actvar.arr[vidx].vd.name;
312 break;
313 }
307 default: 314 default:
308 return; /* other cases cannot be read-only */ 315 lua_assert(e->k == VINDEXI); /* this one doesn't need any check */
316 return; /* integer index cannot be read-only */
309 } 317 }
310 if (varname) 318 if (varname)
311 luaK_semerror(ls, "attempt to assign to const variable '%s'", 319 luaK_semerror(ls, "attempt to assign to const variable '%s'",
@@ -391,7 +399,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
391 399
392 400
393/* 401/*
394** Look for an active local variable with the name 'n' in the 402** Look for an active variable with the name 'n' in the
395** function 'fs'. If found, initialize 'var' with it and return 403** function 'fs'. If found, initialize 'var' with it and return
396** its expression kind; otherwise return -1. 404** its expression kind; otherwise return -1.
397*/ 405*/
@@ -403,7 +411,7 @@ static int searchvar (FuncState *fs, TString *n, expdesc *var) {
403 if (vd->vd.kind == RDKCTC) /* compile-time constant? */ 411 if (vd->vd.kind == RDKCTC) /* compile-time constant? */
404 init_exp(var, VCONST, fs->firstlocal + i); 412 init_exp(var, VCONST, fs->firstlocal + i);
405 else if (vd->vd.kind == GDKREG || vd->vd.kind == GDKCONST) 413 else if (vd->vd.kind == GDKREG || vd->vd.kind == GDKCONST)
406 init_exp(var, VGLOBAL, i); 414 init_exp(var, VGLOBAL, fs->firstlocal + i);
407 else /* local variable */ 415 else /* local variable */
408 init_var(fs, var, i); 416 init_var(fs, var, i);
409 return cast_int(var->k); 417 return cast_int(var->k);
@@ -475,8 +483,11 @@ static void singlevar (LexState *ls, expdesc *var) {
475 singlevaraux(fs, varname, var, 1); 483 singlevaraux(fs, varname, var, 1);
476 if (var->k == VGLOBAL) { /* global name? */ 484 if (var->k == VGLOBAL) { /* global name? */
477 expdesc key; 485 expdesc key;
486 int info = var->u.info;
487 lua_assert(info == -1 ||
488 eqstr(ls->dyd->actvar.arr[info].vd.name, varname));
478 /* global by default in the scope of a global declaration? */ 489 /* global by default in the scope of a global declaration? */
479 if (var->u.info == -1 && fs->bl->globdec) 490 if (info == -1 && fs->bl->globdec)
480 luaK_semerror(ls, "variable '%s' not declared", getstr(varname)); 491 luaK_semerror(ls, "variable '%s' not declared", getstr(varname));
481 singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ 492 singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
482 if (var->k == VGLOBAL) 493 if (var->k == VGLOBAL)
@@ -485,6 +496,7 @@ static void singlevar (LexState *ls, expdesc *var) {
485 luaK_exp2anyregup(fs, var); /* but could be a constant */ 496 luaK_exp2anyregup(fs, var); /* but could be a constant */
486 codestring(&key, varname); /* key is variable name */ 497 codestring(&key, varname); /* key is variable name */
487 luaK_indexed(fs, var, &key); /* env[varname] */ 498 luaK_indexed(fs, var, &key); /* env[varname] */
499 var->u.ind.vidx = cast(short, info); /* mark it as a declared global */
488 } 500 }
489} 501}
490 502
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 {
77 int info; /* for generic use */ 77 int info; /* for generic use */
78 struct { /* for indexed variables */ 78 struct { /* for indexed variables */
79 short idx; /* index (R or "long" K) */ 79 short idx; /* index (R or "long" K) */
80 short vidx; /* index in 'actvar.arr' or -1 if not a declared global */
80 lu_byte t; /* table (register or upvalue) */ 81 lu_byte t; /* table (register or upvalue) */
81 } ind; 82 } ind;
82 struct { /* for local variables */ 83 struct { /* for local variables */
83 lu_byte ridx; /* register holding the variable */ 84 lu_byte ridx; /* register holding the variable */
84 unsigned short vidx; /* compiler index (in 'actvar.arr') */ 85 short vidx; /* index in 'actvar.arr' */
85 } var; 86 } var;
86 } u; 87 } u;
87 int t; /* patch list of 'exit when true' */ 88 int t; /* patch list of 'exit when true' */
@@ -101,7 +102,7 @@ typedef struct expdesc {
101#define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE) 102#define varinreg(v) ((v)->vd.kind <= RDKTOCLOSE)
102 103
103 104
104/* description of an active local variable */ 105/* description of an active variable */
105typedef union Vardesc { 106typedef union Vardesc {
106 struct { 107 struct {
107 TValuefields; /* constant value (if it is a compile-time constant) */ 108 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
178 178
179 179
180do -- constants 180do -- constants
181 global assert<const>, load, string, X
182 X = 1 -- not a constant
181 local a<const>, b, c<const> = 10, 20, 30 183 local a<const>, b, c<const> = 10, 20, 30
182 b = a + c + b -- 'b' is not constant 184 b = a + c + b -- 'b' is not constant
183 assert(a == 10 and b == 60 and c == 30) 185 assert(a == 10 and b == 60 and c == 30)
@@ -191,6 +193,9 @@ do -- constants
191 checkro("z", "local x <const>, y, z <const> = 10, 20, 30; y = 10; z = 11") 193 checkro("z", "local x <const>, y, z <const> = 10, 20, 30; y = 10; z = 11")
192 checkro("foo", "local foo <const> = 10; function foo() end") 194 checkro("foo", "local foo <const> = 10; function foo() end")
193 checkro("foo", "local foo <const> = {}; function foo() end") 195 checkro("foo", "local foo <const> = {}; function foo() end")
196 checkro("foo", "global foo <const>; function foo() end")
197 checkro("XX", "global XX <const>; XX = 10")
198 checkro("XX", "local _ENV; global XX <const>; XX = 10")
194 199
195 checkro("z", [[ 200 checkro("z", [[
196 local a, z <const>, b = 10; 201 local a, z <const>, b = 10;
@@ -201,6 +206,11 @@ do -- constants
201 local a, var1 <const> = 10; 206 local a, var1 <const> = 10;
202 function foo() a = 20; z = function () var1 = 12; end end 207 function foo() a = 20; z = function () var1 = 12; end end
203 ]]) 208 ]])
209
210 checkro("var1", [[
211 global a, var1 <const>, z;
212 local function foo() a = 20; z = function () var1 = 12; end end
213 ]])
204end 214end
205 215
206 216