aboutsummaryrefslogtreecommitdiff
path: root/lfunc.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2021-01-19 10:03:13 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2021-01-19 10:03:13 -0300
commit6ccd24eff58340c00db2877c4558a63c6b859442 (patch)
tree4c8f51657d8d1f4921846a23ba4b475db49fd837 /lfunc.c
parentd0f34d91373fa265d4445e456e4a10ce206c1559 (diff)
downloadlua-6ccd24eff58340c00db2877c4558a63c6b859442.tar.gz
lua-6ccd24eff58340c00db2877c4558a63c6b859442.tar.bz2
lua-6ccd24eff58340c00db2877c4558a63c6b859442.zip
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.
Diffstat (limited to 'lfunc.c')
-rw-r--r--lfunc.c37
1 files changed, 16 insertions, 21 deletions
diff --git a/lfunc.c b/lfunc.c
index 13e44d46..81ac9f0a 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -155,32 +155,19 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
155 155
156 156
157/* 157/*
158** Try to create a to-be-closed upvalue 158** Create a to-be-closed upvalue. If there is a memory allocation error,
159** (can raise a memory-allocation error) 159** 'ptbc' keeps the object so it can be closed as soon as possible.
160*/ 160** (Since memory errors have no handler, that will happen before any
161static void trynewtbcupval (lua_State *L, void *ud) { 161** stack reallocation.)
162 newupval(L, 1, cast(StkId, ud), &L->openupval);
163}
164
165
166/*
167** Create a to-be-closed upvalue. If there is a memory error
168** when creating the upvalue, the closing method must be called here,
169** as there is no upvalue to call it later.
170*/ 162*/
171void luaF_newtbcupval (lua_State *L, StkId level) { 163void luaF_newtbcupval (lua_State *L, StkId level) {
172 TValue *obj = s2v(level); 164 TValue *obj = s2v(level);
173 lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); 165 lua_assert(L->openupval == NULL || uplevel(L->openupval) < level);
174 if (!l_isfalse(obj)) { /* false doesn't need to be closed */ 166 if (!l_isfalse(obj)) { /* false doesn't need to be closed */
175 int status;
176 checkclosemth(L, level, obj); 167 checkclosemth(L, level, obj);
177 status = luaD_rawrunprotected(L, trynewtbcupval, level); 168 L->ptbc = level; /* in case of allocation error */
178 if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ 169 newupval(L, 1, level, &L->openupval);
179 lua_assert(status == LUA_ERRMEM); 170 L->ptbc = NULL; /* no errors */
180 luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */
181 callclosemethod(L, s2v(level), s2v(level + 1), 0);
182 luaD_throw(L, LUA_ERRMEM); /* throw memory error */
183 }
184 } 171 }
185} 172}
186 173
@@ -196,11 +183,19 @@ void luaF_unlinkupval (UpVal *uv) {
196/* 183/*
197** Close all upvalues up to the given stack level. A 'status' equal 184** Close all upvalues up to the given stack level. A 'status' equal
198** to NOCLOSINGMETH closes upvalues without running any __close 185** to NOCLOSINGMETH closes upvalues without running any __close
199** metamethods. 186** metamethods. If there is a pending to-be-closed value, close
187** it before anything else.
200*/ 188*/
201void luaF_close (lua_State *L, StkId level, int status, int yy) { 189void luaF_close (lua_State *L, StkId level, int status, int yy) {
202 UpVal *uv; 190 UpVal *uv;
203 StkId upl; /* stack index pointed by 'uv' */ 191 StkId upl; /* stack index pointed by 'uv' */
192 if (unlikely(status == LUA_ERRMEM && L->ptbc != NULL)) {
193 upl = L->ptbc;
194 L->ptbc = NULL; /* remove from "list" before closing */
195 prepcallclosemth(L, upl, status, yy);
196 }
197 else
198 lua_assert(L->ptbc == NULL); /* must be empty for other status */
204 while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { 199 while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
205 TValue *slot = &uv->u.value; /* new position for value */ 200 TValue *slot = &uv->u.value; /* new position for value */
206 lua_assert(uplevel(uv) < L->top); 201 lua_assert(uplevel(uv) < L->top);