No more to-be-closed functions

To-be-closed variables must contain objects with '__toclose'
metamethods (or nil). Functions were removed for several reasons:

* Functions interact badly with sandboxes. If a sandbox raises
an error to interrupt a script, a to-be-closed function still
can hijack control and continue running arbitrary sandboxed code.

* Functions interact badly with coroutines. If a coroutine yields
and is never resumed again, its to-be-closed functions will never
run. To-be-closed objects, on the other hand, will still be closed,
provided they have appropriate finalizers.

* If you really need a function, it is easy to create a dummy
object to run that function in its '__toclose' metamethod.

This comit also adds closing of variables in case of panic.
This commit is contained in:
Roberto Ierusalimschy
2019-01-04 13:09:47 -02:00
parent c6f7181e91
commit 4ace93ca65
8 changed files with 97 additions and 68 deletions

24
lfunc.c
View File

@@ -100,28 +100,23 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
static void callclose (lua_State *L, void *ud) {
UNUSED(ud);
luaD_callnoyield(L, L->top - 2, 0);
luaD_callnoyield(L, L->top - 3, 0);
}
/*
** Prepare closing method plus its argument for object 'obj' with
** Prepare closing method plus its arguments for object 'obj' with
** error message 'err'. (This function assumes EXTRA_STACK.)
*/
static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) {
StkId top = L->top;
if (ttisfunction(obj)) { /* object to-be-closed is a function? */
setobj2s(L, top, obj); /* push function */
setobj2s(L, top + 1, err); /* push error msg. as argument */
}
else { /* try '__close' metamethod */
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
if (ttisnil(tm)) /* no metamethod? */
return 0; /* nothing to call */
setobj2s(L, top, tm); /* will call metamethod... */
setobj2s(L, top + 1, obj); /* with 'self' as the argument */
}
L->top = top + 2; /* add function and argument */
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
if (ttisnil(tm)) /* no metamethod? */
return 0; /* nothing to call */
setobj2s(L, top, tm); /* will call metamethod... */
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
L->top = top + 3; /* add function and arguments */
return 1;
}
@@ -156,6 +151,7 @@ static int callclosemth (lua_State *L, TValue *uv, StkId level, int status) {
if (newstatus != LUA_OK) /* another error when closing? */
status = newstatus; /* this will be the new error */
}
/* else no metamethod; ignore this case and keep original error */
}
return status;
}