From 1e64c1391f9a14115b5cc82066dbf545ae73ee27 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Tue, 25 Oct 2022 16:44:06 -0300 Subject: [PATCH] Bug: stack overflow with nesting of coroutine.close --- lcorolib.c | 4 ++-- lstate.c | 3 ++- ltests.c | 2 +- lua.h | 2 +- manual/manual.of | 7 ++++++- testes/cstack.lua | 26 ++++++++++++++++++++++++++ 6 files changed, 38 insertions(+), 6 deletions(-) diff --git a/lcorolib.c b/lcorolib.c index 785a1e81a..40b880b14 100644 --- a/src/lcorolib.c +++ b/src/lcorolib.c @@ -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; diff --git a/lstate.c b/lstate.c index 1ffe1a0f7..4b5c10008 100644 --- a/src/lstate.c +++ b/src/lstate.c @@ -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; diff --git a/lua.h b/lua.h index 219784cc0..bfba4d1e1 100644 --- a/src/lua.h +++ b/src/lua.h @@ -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/testes/cstack.lua b/testes/cstack.lua index ca76c8729..97afe9fd0 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 = 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