lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Tried to implement this, the patch came out quite small, and not
even complete, e.g. getfenv is simply missing.
I'm sure I got it wrong at places, but I like the idea of not having
separate concept of environment.

Basically, it gives:
 - even slower global access (double indirection)
 - but now environment can be any value
 - and I think it solves the sandboxing part

I added code to parser that creates unbound upvalue 0 with name "_G",
that is bound to environment on closure instantiation, and has index 0 in C API; changed 'in .. do .. end' also to create '_G' (now it's equal to do local _G = ..; .. end)
and changed code generated by singlevar.

Here's test:

local p = print
in { a=1, b=2 } do
p(a)
p(_G.b)
_G = { a=3, b=4 }
p(a)
local _G = { a=5, b=6 }
p(a)
end

print(_G.a)

Which prints:
1
2
3
5
nil

The sondboxing solution comes from the fact that upvalues are shared, not copied by
value like the environment references, so that:
local f = loadstring(s)
_G = newenv -- this updates all references to old _G inside f
f()

==8<=== Incomplete and flawed patch, against work2




--- lua-5.2.0-work2/src/lparser.c	2010-01-06 13:48:02.000000000 +0200
+++ l520w2-dyen/src/lparser.c	2010-01-19 08:52:45.000000000 +0200
@@ -250,8 +250,9 @@


static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
-  if (fs == NULL)  /* no more levels? */
+  if (fs == NULL) { /* no more levels? */
     return VGLOBAL;  /* default is global variable */
+  }
   else {
     int v = searchvar(fs, n);  /* look up at current level */
     if (v >= 0) {
@@ -261,7 +262,11 @@
       return VLOCAL;
     }
     else {  /* not found at current level; try upper one */
-      if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL)
+      if (!fs->prev && n == fs->ls->globalname) {
+        init_exp(var, VUPVAL, 0);
+        return VUPVAL;
+      }
+      else if (singlevaraux(fs->prev, n, var, 0) == VGLOBAL)
         return VGLOBAL;
var->u.s.info = indexupvalue(fs, n, var); /* else was LOCAL or UPVAL */
       var->k = VUPVAL;  /* upvalue in this level */
@@ -275,15 +280,12 @@
   TString *varname = str_checkname(ls);
   FuncState *fs = ls->fs;
   if (singlevaraux(fs, varname, var, 1) == VGLOBAL) {
-    if (fs->envreg == NO_REG)  /* regular global? */
-      init_exp(var, VGLOBAL, luaK_stringK(fs, varname));
-    else {  /* "globals" are in current lexical environment */
       expdesc key;
-      init_exp(var, VLOCAL, fs->envreg);  /* current environment */
+    singlevaraux(fs, ls->globalname, var, 1);
+    if (var->k != VLOCAL) luaK_exp2anyreg(fs, var);
       codestring(ls, &key, varname);  /* key is variable name */
       luaK_indexed(fs, var, &key);  /* env[varname] */
     }
-  }
 }


@@ -351,7 +353,6 @@
   while (oldsize < f->sizep) f->p[oldsize++] = NULL;
   f->p[fs->np++] = clp;
/* initial environment for new function is current lexical environment */
-  clp->envreg = fs->envreg;
   luaC_objbarrier(ls->L, f, clp);
   init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1));
 }
@@ -374,7 +375,6 @@
   fs->nlocvars = 0;
   fs->nactvar = 0;
   fs->firstlocal = ls->varl->nactvar;
-  fs->envreg = NO_REG;
   fs->bl = NULL;
   f = luaF_newproto(L);
   fs->f = f;
@@ -429,6 +429,21 @@
   lexstate.varl = varl;
   luaX_setinput(L, &lexstate, z, tname);
   open_func(&lexstate, &funcstate);
+  { /* create local environment */
+    LexState *ls = &lexstate;
+    FuncState *fs = &funcstate;
+    Proto *f = fs->f;
+    expdesc e;
+    e.k = VVOID;
+    ls->globalname = luaX_newstring(ls, "_G", 2);
+    luaC_objbarrier(fs->L, f, ls->globalname);
+    luaM_growvector(fs->L, f->upvalues, fs->nups, f->sizeupvalues,
+                  Upvaldesc, UCHAR_MAX, "upvalues");
+    f->upvalues[0].name = ls->globalname;
+    f->upvalues[0].instack = 0;
+    f->upvalues[0].idx = cast_byte(0);
+    fs->nups++;
+  }
   funcstate.f->is_vararg = 1;  /* main function is always vararg */
   luaX_next(&lexstate);  /* read first token */
   chunk(&lexstate);
@@ -436,7 +451,7 @@
   close_func(&lexstate);
   L->top--;  /* pop name */
   lua_assert(funcstate.prev == NULL);
-  lua_assert(funcstate.nups == 0);
+  lua_assert(funcstate.nups == 1);
   lua_assert(lexstate.fs == NULL);
   return funcstate.f;
 }
@@ -1277,18 +1292,16 @@
 static void instat (LexState *ls, int line) {
   /* instat -> IN exp DO block END */
   FuncState *fs = ls->fs;
-  int oldenv = fs->envreg;  /* save current environment */
   BlockCnt bl;
   luaX_next(ls);  /* skip IN */
   enterblock(fs, &bl, 0);  /* scope for environment variable */
-  new_localvarliteral(ls, "(environment)");
-  fs->envreg = exp1(ls);  /* new environment */
+  new_localvar(ls, ls->globalname);
+  exp1(ls);  /* new environment */
   adjustlocalvars(ls, 1);
   checknext(ls, TK_DO);
   block(ls);
   leaveblock(fs);
   check_match(ls, TK_END, TK_IN, line);
-  fs->envreg = oldenv;  /* restore outer environment */
 }