diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-16 15:17:47 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-16 15:17:47 -0300 |
commit | c220b0a5d099372e58e517b9f13eaa7bb0bec45c (patch) | |
tree | 5d5a083a4a7e924f5af052295cef49792305a989 /lfunc.c | |
parent | 298f383ffcc30d0799fbca0293175f647fe6bccf (diff) | |
download | lua-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.c | 22 |
1 files changed, 12 insertions, 10 deletions
@@ -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 | */ |
136 | static int callclosemth (lua_State *L, TValue *uv, StkId level, int status) { | 136 | static 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 | } |