diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-12-21 15:21:45 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-12-21 15:21:45 -0300 |
| commit | f9d29b0c442447ebe429bcaad1e2b4bf13c5dc93 (patch) | |
| tree | 05864d5bb96e6efe207e7d7eeff0fd251494562b /lfunc.c | |
| parent | 409256b7849ec5ab3296cb0ab9eba3d65955d5ea (diff) | |
| download | lua-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.c | 30 |
1 files changed, 22 insertions, 8 deletions
| @@ -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 | */ | ||
| 223 | int luaF_close (lua_State *L, StkId level, int status) { | 236 | int 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 | } |
