aboutsummaryrefslogtreecommitdiff
path: root/lfunc.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-07-16 15:17:47 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-07-16 15:17:47 -0300
commitc220b0a5d099372e58e517b9f13eaa7bb0bec45c (patch)
tree5d5a083a4a7e924f5af052295cef49792305a989 /lfunc.c
parent298f383ffcc30d0799fbca0293175f647fe6bccf (diff)
downloadlua-c220b0a5d099372e58e517b9f13eaa7bb0bec45c.tar.gz
lua-c220b0a5d099372e58e517b9f13eaa7bb0bec45c.tar.bz2
lua-c220b0a5d099372e58e517b9f13eaa7bb0bec45c.zip
'__close' method may be called again in case of error
An error in a closing method may be caused by a lack of resources, such as memory or stack space, and the error may free enough resources (by unwinding the stack) to allow the method to work if called again. If the closing method is already running after some error (including its own), it is not called again.
Diffstat (limited to 'lfunc.c')
-rw-r--r--lfunc.c22
1 files changed, 12 insertions, 10 deletions
diff --git a/lfunc.c b/lfunc.c
index 68d0632a..cd85cc1f 100644
--- a/lfunc.c
+++ b/lfunc.c
@@ -133,7 +133,8 @@ static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) {
133** the 'level' of the upvalue being closed, as everything after 133** the 'level' of the upvalue being closed, as everything after
134** that won't be used again. 134** that won't be used again.
135*/ 135*/
136static int callclosemth (lua_State *L, TValue *uv, StkId level, int status) { 136static int callclosemth (lua_State *L, StkId level, int status) {
137 TValue *uv = s2v(level); /* value being closed */
137 if (likely(status == LUA_OK)) { 138 if (likely(status == LUA_OK)) {
138 if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */ 139 if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */
139 callclose(L, NULL); /* call closing method */ 140 callclose(L, NULL); /* call closing method */
@@ -145,9 +146,10 @@ static int callclosemth (lua_State *L, TValue *uv, StkId level, int status) {
145 } 146 }
146 } 147 }
147 else { /* must close the object in protected mode */ 148 else { /* must close the object in protected mode */
148 ptrdiff_t oldtop = savestack(L, level + 1); 149 ptrdiff_t oldtop;
149 /* save error message and set stack top to 'level + 1' */ 150 level++; /* space for error message */
150 luaD_seterrorobj(L, status, level); 151 oldtop = savestack(L, level + 1); /* top will be after that */
152 luaD_seterrorobj(L, status, level); /* set error message */
151 if (prepclosingmethod(L, uv, s2v(level))) { /* something to call? */ 153 if (prepclosingmethod(L, uv, s2v(level))) { /* something to call? */
152 int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0); 154 int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0);
153 if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */ 155 if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */
@@ -203,18 +205,18 @@ int luaF_close (lua_State *L, StkId level, int status) {
203 StkId upl = uplevel(uv); 205 StkId upl = uplevel(uv);
204 TValue *slot = &uv->u.value; /* new position for value */ 206 TValue *slot = &uv->u.value; /* new position for value */
205 lua_assert(upl < L->top); 207 lua_assert(upl < L->top);
208 if (uv->tt == LUA_TUPVALTBC && status != NOCLOSINGMETH) {
209 /* must run closing method */
210 ptrdiff_t levelrel = savestack(L, level);
211 status = callclosemth(L, upl, status); /* may change the stack */
212 level = restorestack(L, levelrel);
213 }
206 luaF_unlinkupval(uv); 214 luaF_unlinkupval(uv);
207 setobj(L, slot, uv->v); /* move value to upvalue slot */ 215 setobj(L, slot, uv->v); /* move value to upvalue slot */
208 uv->v = slot; /* now current value lives here */ 216 uv->v = slot; /* now current value lives here */
209 if (!iswhite(uv)) 217 if (!iswhite(uv))
210 gray2black(uv); /* closed upvalues cannot be gray */ 218 gray2black(uv); /* closed upvalues cannot be gray */
211 luaC_barrier(L, uv, slot); 219 luaC_barrier(L, uv, slot);
212 if (uv->tt == LUA_TUPVALTBC && status != NOCLOSINGMETH) {
213 /* must run closing method */
214 ptrdiff_t levelrel = savestack(L, level);
215 status = callclosemth(L, uv->v, upl, status); /* may change the stack */
216 level = restorestack(L, levelrel);
217 }
218 } 220 }
219 return status; 221 return status;
220} 222}