[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: environment as upvalue
- From: "Juris Kalnins" <juris@...>
- Date: Tue, 19 Jan 2010 09:08:00 +0200
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 */
}