aboutsummaryrefslogtreecommitdiff
path: root/lfunc.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-12-21 15:21:45 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2020-12-21 15:21:45 -0300
commitf9d29b0c442447ebe429bcaad1e2b4bf13c5dc93 (patch)
tree05864d5bb96e6efe207e7d7eeff0fd251494562b /lfunc.c
parent409256b7849ec5ab3296cb0ab9eba3d65955d5ea (diff)
downloadlua-f9d29b0c442447ebe429bcaad1e2b4bf13c5dc93.tar.gz
lua-f9d29b0c442447ebe429bcaad1e2b4bf13c5dc93.tar.bz2
lua-f9d29b0c442447ebe429bcaad1e2b4bf13c5dc93.zip
Upvalues removed from 'openupval' before being closed
Undo commit c220b0a5d0: '__close' is not called again in case of errors. (Upvalue is removed from the list before the call.) The common error that justified that change was C stack overflows, which are much rarer with the stackless implementation.
Diffstat (limited to 'lfunc.c')
-rw-r--r--lfunc.c30
1 files changed, 22 insertions, 8 deletions
diff --git a/lfunc.c b/lfunc.c
index c4360f09..6608592b 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -220,24 +220,38 @@ void luaF_unlinkupval (UpVal *uv) {
220} 220}
221 221
222 222
223/*
224** Close all upvalues up to the given stack level. 'status' indicates
225** how/why the function was called:
226** - LUA_OK: regular code exiting the scope of a variable; may raise
227** an error due to errors in __close metamethods;
228** - CLOSEPROTECT: finishing a thread; run all metamethods in protected
229** mode;
230** - NOCLOSINGMETH: close upvalues without running __close metamethods;
231** - other values: error status from previous errors, to be propagated.
232**
233** Returns the resulting status, either the original status or an error
234** in a closing method.
235*/
223int luaF_close (lua_State *L, StkId level, int status) { 236int luaF_close (lua_State *L, StkId level, int status) {
224 UpVal *uv; 237 UpVal *uv;
225 while ((uv = L->openupval) != NULL && uplevel(uv) >= level) { 238 StkId upl; /* stack index pointed by 'uv' */
239 while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
226 TValue *slot = &uv->u.value; /* new position for value */ 240 TValue *slot = &uv->u.value; /* new position for value */
227 lua_assert(uplevel(uv) < L->top); 241 lua_assert(uplevel(uv) < L->top);
228 if (uv->tbc && status != NOCLOSINGMETH) { 242 luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
229 /* must run closing method, which may change the stack */
230 ptrdiff_t levelrel = savestack(L, level);
231 status = callclosemth(L, uplevel(uv), status);
232 level = restorestack(L, levelrel);
233 }
234 luaF_unlinkupval(uv);
235 setobj(L, slot, uv->v); /* move value to upvalue slot */ 243 setobj(L, slot, uv->v); /* move value to upvalue slot */
236 uv->v = slot; /* now current value lives here */ 244 uv->v = slot; /* now current value lives here */
237 if (!iswhite(uv)) { /* neither white nor dead? */ 245 if (!iswhite(uv)) { /* neither white nor dead? */
238 nw2black(uv); /* closed upvalues cannot be gray */ 246 nw2black(uv); /* closed upvalues cannot be gray */
239 luaC_barrier(L, uv, slot); 247 luaC_barrier(L, uv, slot);
240 } 248 }
249 if (uv->tbc && status != NOCLOSINGMETH) {
250 /* must run closing method, which may change the stack */
251 ptrdiff_t levelrel = savestack(L, level);
252 status = callclosemth(L, upl, status);
253 level = restorestack(L, levelrel);
254 }
241 } 255 }
242 return status; 256 return status;
243} 257}