diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2022-10-25 16:44:06 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2022-10-25 16:44:06 -0300 |
commit | 1e64c1391f9a14115b5cc82066dbf545ae73ee27 (patch) | |
tree | 4aa3b6c2854c920ed825bf9fe46d275826e5ab6e | |
parent | b85816b9a884cbe4cfd139a8e11ffc28ecead576 (diff) | |
download | lua-github-1e64c1391f9a14115b5cc82066dbf545ae73ee27.tar.gz |
Bug: stack overflow with nesting of coroutine.close
-rw-r--r-- | lcorolib.c | 4 | ||||
-rw-r--r-- | lstate.c | 3 | ||||
-rw-r--r-- | ltests.c | 2 | ||||
-rw-r--r-- | lua.h | 2 | ||||
-rw-r--r-- | manual/manual.of | 7 | ||||
-rw-r--r-- | testes/cstack.lua | 26 |
6 files changed, 38 insertions, 6 deletions
@@ -76,7 +76,7 @@ static int luaB_auxwrap (lua_State *L) { if (l_unlikely(r < 0)) { /* error? */ int stat = lua_status(co); if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ - stat = lua_resetthread(co); /* close its tbc variables */ + stat = lua_resetthread(co, L); /* close its tbc variables */ lua_assert(stat != LUA_OK); lua_xmove(co, L, 1); /* move error message to the caller */ } @@ -172,7 +172,7 @@ static int luaB_close (lua_State *L) { int status = auxstatus(L, co); switch (status) { case COS_DEAD: case COS_YIELD: { - status = lua_resetthread(co); + status = lua_resetthread(co, L); if (status == LUA_OK) { lua_pushboolean(L, 1); return 1; @@ -343,9 +343,10 @@ int luaE_resetthread (lua_State *L, int status) { } -LUA_API int lua_resetthread (lua_State *L) { +LUA_API int lua_resetthread (lua_State *L, lua_State *from) { int status; lua_lock(L); + L->nCcalls = (from) ? getCcalls(from) : 0; status = luaE_resetthread(L, L->status); lua_unlock(L); return status; @@ -1533,7 +1533,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { lua_newthread(L1); } else if EQ("resetthread") { - lua_pushinteger(L1, lua_resetthread(L1)); + lua_pushinteger(L1, lua_resetthread(L1, L)); } else if EQ("newuserdata") { lua_newuserdata(L1, getnum); @@ -153,7 +153,7 @@ extern const char lua_ident[]; LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); LUA_API void (lua_close) (lua_State *L); LUA_API lua_State *(lua_newthread) (lua_State *L); -LUA_API int (lua_resetthread) (lua_State *L); +LUA_API int (lua_resetthread) (lua_State *L, lua_State *from); LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); diff --git a/manual/manual.of b/manual/manual.of index 10c16bd1..6d19e251 100644 --- a/manual/manual.of +++ b/manual/manual.of @@ -4160,7 +4160,7 @@ and then pops the top element. } -@APIEntry{int lua_resetthread (lua_State *L);| +@APIEntry{int lua_resetthread (lua_State *L, lua_State *from);| @apii{0,?,-} Resets a thread, cleaning its call stack and closing all pending @@ -4173,6 +4173,11 @@ or an error status otherwise. In case of error, leaves the error object on the top of the stack. +The parameter @id{from} represents the coroutine that is resetting @id{L}. +If there is no such coroutine, +this parameter can be @id{NULL}. +(This parameter was introduced in @N{release 5.4.5}.) + } @APIEntry{int lua_resume (lua_State *L, lua_State *from, int nargs, diff --git a/testes/cstack.lua b/testes/cstack.lua index ca76c872..97afe9fd 100644 --- a/testes/cstack.lua +++ b/testes/cstack.lua @@ -84,6 +84,32 @@ do -- bug in 5.4.0 end +do -- bug since 5.4.0 + local count = 0 + print("chain of 'coroutine.close'") + -- create N coroutines forming a list so that each one, when closed, + -- closes the previous one. (With a large enough N, previous Lua + -- versions crash in this test.) + local coro = false + for i = 1, 1000 do + local previous = coro + coro = coroutine.create(function() + local cc <close> = setmetatable({}, {__close=function() + count = count + 1 + if previous then + assert(coroutine.close(previous)) + end + end}) + coroutine.yield() -- leaves 'cc' pending to be closed + end) + assert(coroutine.resume(coro)) -- start it and run until it yields + end + local st, msg = coroutine.close(coro) + assert(not st and string.find(msg, "C stack overflow")) + print("final count: ", count) +end + + do print("nesting of resuming yielded coroutines") local count = 0 |