diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-11-08 11:55:25 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-11-08 11:55:25 -0300 |
commit | bfbff3703edae789fa5efa9bf174f8e7cff4ded8 (patch) | |
tree | 5e8466f78f52b5d53691f800354a3aed313d11a9 | |
parent | 74d99057a5146755e737c479850f87fd0e3b6868 (diff) | |
download | lua-github-bfbff3703edae789fa5efa9bf174f8e7cff4ded8.tar.gz |
Bug: Wrong status in coroutine during reset
When closing variables during 'coroutine.close' or 'lua_resetthread',
the status of a coroutine must be set to LUA_OK; a coroutine should
not run with any other status. (See assertion in 'lua_callk'.)
After the reset, the status should be kept as normal, as any error
was already reported.
-rw-r--r-- | lcorolib.c | 4 | ||||
-rw-r--r-- | lstate.c | 4 | ||||
-rw-r--r-- | testes/coroutine.lua | 44 |
3 files changed, 47 insertions, 5 deletions
@@ -78,7 +78,7 @@ static int luaB_auxwrap (lua_State *L) { if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ stat = lua_resetthread(co); /* close its tbc variables */ lua_assert(stat != LUA_OK); - lua_xmove(co, L, 1); /* copy error message */ + lua_xmove(co, L, 1); /* move error message to the caller */ } if (stat != LUA_ERRMEM && /* not a memory error and ... */ lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */ @@ -179,7 +179,7 @@ static int luaB_close (lua_State *L) { } else { lua_pushboolean(L, 0); - lua_xmove(co, L, 1); /* copy error message */ + lua_xmove(co, L, 1); /* move error message */ return 2; } } @@ -166,7 +166,7 @@ void luaE_checkcstack (lua_State *L) { if (getCcalls(L) == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11)) - luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ + luaD_throw(L, LUA_ERRERR); /* error while handling stack error */ } @@ -330,13 +330,13 @@ int luaE_resetthread (lua_State *L, int status) { ci->callstatus = CIST_C; if (status == LUA_YIELD) status = LUA_OK; + L->status = LUA_OK; /* so it can run __close metamethods */ status = luaD_closeprotected(L, 1, status); if (status != LUA_OK) /* errors? */ luaD_seterrorobj(L, status, L->stack + 1); else L->top = L->stack + 1; ci->top = L->top + LUA_MINSTACK; - L->status = cast_byte(status); luaD_reallocstack(L, cast_int(ci->top - L->stack), 0); return status; } diff --git a/testes/coroutine.lua b/testes/coroutine.lua index 461e0377..76c9d6e6 100644 --- a/testes/coroutine.lua +++ b/testes/coroutine.lua @@ -136,6 +136,10 @@ do assert(coroutine.status(co) == "dead") local st, msg = coroutine.close(co) assert(st and msg == nil) + -- also ok to close it again + st, msg = coroutine.close(co) + assert(st and msg == nil) + -- cannot close the running coroutine local st, msg = pcall(coroutine.close, coroutine.running()) @@ -149,6 +153,22 @@ do assert(not st and string.find(msg, "normal")) end))() + -- cannot close a coroutine while closing it + do + local co + co = coroutine.create( + function() + local x <close> = func2close(function() + coroutine.close(co) -- try to close it again + end) + coroutine.yield(20) + end) + local st, msg = coroutine.resume(co) + assert(st and msg == 20) + st, msg = coroutine.close(co) + assert(not st and string.find(msg, "running coroutine")) + end + -- to-be-closed variables in coroutines local X @@ -158,6 +178,9 @@ do assert(not st and msg == 100) st, msg = coroutine.close(co) assert(not st and msg == 100) + -- after closing, no more errors + st, msg = coroutine.close(co) + assert(st and msg == nil) co = coroutine.create(function () local x <close> = func2close(function (self, err) @@ -189,6 +212,9 @@ do local st, msg = coroutine.close(co) assert(st == false and coroutine.status(co) == "dead" and msg == 200) assert(x == 200) + -- after closing, no more errors + st, msg = coroutine.close(co) + assert(st and msg == nil) end do @@ -419,7 +445,7 @@ do local X = false A = coroutine.wrap(function() - local _ <close> = setmetatable({}, {__close = function () X = true end}) + local _ <close> = func2close(function () X = true end) return pcall(A, 1) end) st, res = A() @@ -427,6 +453,22 @@ do end +-- bug in 5.4.1 +do + -- coroutine ran close metamethods with invalid status during a + -- reset. + local co + co = coroutine.wrap(function() + local x <close> = func2close(function() return pcall(co) end) + error(111) + end) + local st, errobj = pcall(co) + assert(not st and errobj == 111) + st, errobj = pcall(co) + assert(not st and string.find(errobj, "dead coroutine")) +end + + -- attempt to resume 'normal' coroutine local co1, co2 co1 = coroutine.create(function () return co2() end) |