mirror of
https://github.com/lua/lua.git
synced 2026-10-27 11:05:25 +00:00
Bug: Calling coroutine.close while closing after error
A call to 'coroutine.close()' while closing the coroutine returns like 'resume', with no errors, even if the coroutine previously had stopped due to an error.
This commit is contained in:
+2
-1
@@ -78,7 +78,8 @@ static int luaB_auxwrap (lua_State *L) {
|
||||
int stat = lua_status(co);
|
||||
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
|
||||
stat = lua_closethread(co, L); /* close its tbc variables */
|
||||
lua_assert(stat != LUA_OK);
|
||||
if (stat == LUA_OK)
|
||||
return 0; /* nothing to return */
|
||||
lua_xmove(co, L, 1); /* move error message to the caller */
|
||||
}
|
||||
if (stat != LUA_ERRMEM && /* not a memory error and ... */
|
||||
|
||||
@@ -319,18 +319,36 @@ TStatus luaE_resetthread (lua_State *L, TStatus status) {
|
||||
status = luaD_closeprotected(L, 1, status);
|
||||
if (status != LUA_OK) /* errors? */
|
||||
luaD_seterrorobj(L, status, L->stack.p + 1);
|
||||
else
|
||||
else /* keep in the stack only the fake function-entry for basic ci */
|
||||
L->top.p = L->stack.p + 1;
|
||||
luaD_reallocstack(L, cast_int(L->ci->top.p - L->stack.p), 0);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Auxiliary function to call luaE_resetthread in protected mode.
|
||||
** That function closes all tbc variables in protected mode, so the
|
||||
** only possible "error" is when a tbc variable closes the thread being
|
||||
** closed and therefore calls 'luaD_throwbaselevel'; in that case,
|
||||
** control goes directly back to the first call to lua_closethread (not
|
||||
** to the second), to properly return it.
|
||||
*/
|
||||
static void resetthread_aux (lua_State *L, void *ud) {
|
||||
TStatus status = *cast(TStatus*, ud);
|
||||
status = luaE_resetthread(L, status);
|
||||
if (status != LUA_OK)
|
||||
luaD_throw(L, status);
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_closethread (lua_State *L, lua_State *from) {
|
||||
TStatus status;
|
||||
lua_lock(L);
|
||||
L->nCcalls = (from) ? getCcalls(from) : 0;
|
||||
status = luaE_resetthread(L, L->status);
|
||||
status = luaD_rawrunprotected(L, resetthread_aux, &L->status);
|
||||
/* stack has error message iff there was an error */
|
||||
lua_assert(L->top.p == L->stack.p + (status == LUA_OK ? 1 : 2));
|
||||
if (L == from) /* closing itself? */
|
||||
luaD_throwbaselevel(L, status);
|
||||
lua_unlock(L);
|
||||
|
||||
+2
-1
@@ -7048,7 +7048,8 @@ The given coroutine must be dead, suspended,
|
||||
or be the running coroutine.
|
||||
For the running coroutine,
|
||||
this function does not return.
|
||||
Instead, the resume that (re)started the coroutine returns.
|
||||
Instead, the resume that (re)started the coroutine returns
|
||||
with no error and no results.
|
||||
|
||||
For other coroutines,
|
||||
in case of error
|
||||
|
||||
+18
-2
@@ -156,8 +156,6 @@ do
|
||||
st, msg = coroutine.close(co)
|
||||
assert(st and msg == nil)
|
||||
|
||||
local main = coroutine.running()
|
||||
|
||||
-- cannot close 'main'
|
||||
local st, msg = pcall(coroutine.close, main);
|
||||
assert(not st and string.find(msg, "main"))
|
||||
@@ -184,6 +182,24 @@ do
|
||||
assert(st and msg == nil)
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
-- again close a coroutine while closing it, but with the
|
||||
-- coroutine in error mode.
|
||||
|
||||
-- after the error, the function created by 'wrap' will close the
|
||||
-- coroutine. The close inside 'a' overrides the original close
|
||||
-- and finishes the coroutine with no errors.
|
||||
local co = coroutine.wrap(function()
|
||||
local a <close> = func2close(function()
|
||||
coroutine.close()
|
||||
end)
|
||||
error("y")
|
||||
end)
|
||||
co() -- no errors
|
||||
end
|
||||
|
||||
|
||||
-- to-be-closed variables in coroutines
|
||||
local X
|
||||
|
||||
|
||||
Reference in New Issue
Block a user