lua-users home
lua-l archive

environment as upvalue

[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 */
 }

AltStyle によって変換されたページ (->オリジナル) /