Browse Source

Checks for read-only globals

Roberto Ierusalimschy 2 months ago
parent
commit
4365a45d68
4 changed files with 33 additions and 9 deletions
  1. 2 1
      lcode.c
  2. 18 6
      lparser.c
  3. 3 2
      lparser.h
  4. 10 0
      testes/locals.lua

+ 2 - 1
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 */
 }
 
 

+ 18 - 6
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 */
   }
 }
 

+ 3 - 2
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) */

+ 10 - 0
testes/locals.lua

@@ -178,6 +178,8 @@ A = nil
 
 
 do   -- constants
+  global assert<const>, load, string, X
+  X = 1   -- not a constant
   local a<const>, b, c<const> = 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 <const>, y, z <const> = 10, 20, 30; y = 10; z = 11")
   checkro("foo", "local foo <const> = 10; function foo() end")
   checkro("foo", "local foo <const> = {}; function foo() end")
+  checkro("foo", "global foo <const>; function foo() end")
+  checkro("XX", "global XX <const>; XX = 10")
+  checkro("XX", "local _ENV; global XX <const>; XX = 10")
 
   checkro("z", [[
     local a, z <const>, b = 10;
@@ -201,6 +206,11 @@ do   -- constants
     local a, var1 <const> = 10;
     function foo() a = 20; z = function () var1 = 12; end  end
   ]])
+
+  checkro("var1", [[
+    global a, var1 <const>, z;
+    local function foo() a = 20; z = function () var1 = 12; end  end
+  ]])
 end