diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-05-06 15:54:05 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2025-05-06 15:54:05 -0300 |
| commit | 4365a45d681b4e71e3c39148489bb8eae538ccf7 (patch) | |
| tree | ea22f0836f252edd7bc7279772158f2b7e549b1e | |
| parent | be8120906304a8658fab998587b969e0e42f5650 (diff) | |
| download | lua-4365a45d681b4e71e3c39148489bb8eae538ccf7.tar.gz lua-4365a45d681b4e71e3c39148489bb8eae538ccf7.tar.bz2 lua-4365a45d681b4e71e3c39148489bb8eae538ccf7.zip | |
Checks for read-only globals
| -rw-r--r-- | lcode.c | 3 | ||||
| -rw-r--r-- | lparser.c | 24 | ||||
| -rw-r--r-- | lparser.h | 5 | ||||
| -rw-r--r-- | testes/locals.lua | 10 |
4 files changed, 33 insertions, 9 deletions
| @@ -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 | ||
| @@ -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) { | |||
| 276 | static void init_var (FuncState *fs, expdesc *e, int vidx) { | 276 | static 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 | ||
| @@ -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 */ |
| 105 | typedef union Vardesc { | 106 | typedef 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 | ||
| 180 | do -- constants | 180 | do -- 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 | ]]) | ||
| 204 | end | 214 | end |
| 205 | 215 | ||
| 206 | 216 | ||
