Simpler handling of errors when creating tbc variables

New field 'lua_State.ptbc' keeps to-be-closed variable until its
upvalue is created, so that it can be closed in case of a
memory-allocation error.
This commit is contained in:
Roberto Ierusalimschy
2021-01-19 10:03:13 -03:00
parent d0f34d9137
commit 6ccd24eff5
6 changed files with 25 additions and 35 deletions

37
lfunc.c
View File

@@ -155,32 +155,19 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
/*
** Try to create a to-be-closed upvalue
** (can raise a memory-allocation error)
*/
static void trynewtbcupval (lua_State *L, void *ud) {
newupval(L, 1, cast(StkId, ud), &L->openupval);
}
/*
** Create a to-be-closed upvalue. If there is a memory error
** when creating the upvalue, the closing method must be called here,
** as there is no upvalue to call it later.
** Create a to-be-closed upvalue. If there is a memory allocation error,
** 'ptbc' keeps the object so it can be closed as soon as possible.
** (Since memory errors have no handler, that will happen before any
** stack reallocation.)
*/
void luaF_newtbcupval (lua_State *L, StkId level) {
TValue *obj = s2v(level);
lua_assert(L->openupval == NULL || uplevel(L->openupval) < level);
if (!l_isfalse(obj)) { /* false doesn't need to be closed */
int status;
checkclosemth(L, level, obj);
status = luaD_rawrunprotected(L, trynewtbcupval, level);
if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */
lua_assert(status == LUA_ERRMEM);
luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */
callclosemethod(L, s2v(level), s2v(level + 1), 0);
luaD_throw(L, LUA_ERRMEM); /* throw memory error */
}
L->ptbc = level; /* in case of allocation error */
newupval(L, 1, level, &L->openupval);
L->ptbc = NULL; /* no errors */
}
}
@@ -196,11 +183,19 @@ void luaF_unlinkupval (UpVal *uv) {
/*
** Close all upvalues up to the given stack level. A 'status' equal
** to NOCLOSINGMETH closes upvalues without running any __close
** metamethods.
** metamethods. If there is a pending to-be-closed value, close
** it before anything else.
*/
void luaF_close (lua_State *L, StkId level, int status, int yy) {
UpVal *uv;
StkId upl; /* stack index pointed by 'uv' */
if (unlikely(status == LUA_ERRMEM && L->ptbc != NULL)) {
upl = L->ptbc;
L->ptbc = NULL; /* remove from "list" before closing */
prepcallclosemth(L, upl, status, yy);
}
else
lua_assert(L->ptbc == NULL); /* must be empty for other status */
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
TValue *slot = &uv->u.value; /* new position for value */
lua_assert(uplevel(uv) < L->top);