aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2022-10-25 16:44:06 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2022-10-25 16:44:06 -0300
commit1e64c1391f9a14115b5cc82066dbf545ae73ee27 (patch)
tree4aa3b6c2854c920ed825bf9fe46d275826e5ab6e
parentb85816b9a884cbe4cfd139a8e11ffc28ecead576 (diff)
downloadlua-1e64c1391f9a14115b5cc82066dbf545ae73ee27.tar.gz
lua-1e64c1391f9a14115b5cc82066dbf545ae73ee27.tar.bz2
lua-1e64c1391f9a14115b5cc82066dbf545ae73ee27.zip
Bug: stack overflow with nesting of coroutine.close
-rw-r--r--lcorolib.c4
-rw-r--r--lstate.c3
-rw-r--r--ltests.c2
-rw-r--r--lua.h2
-rw-r--r--manual/manual.of7
-rw-r--r--testes/cstack.lua26
6 files changed, 38 insertions, 6 deletions
diff --git a/lcorolib.c b/lcorolib.c
index 785a1e81..40b880b1 100644
--- a/lcorolib.c
+++ b/lcorolib.c
@@ -76,7 +76,7 @@ static int luaB_auxwrap (lua_State *L) {
76 if (l_unlikely(r < 0)) { /* error? */ 76 if (l_unlikely(r < 0)) { /* error? */
77 int stat = lua_status(co); 77 int stat = lua_status(co);
78 if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ 78 if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
79 stat = lua_resetthread(co); /* close its tbc variables */ 79 stat = lua_resetthread(co, L); /* close its tbc variables */
80 lua_assert(stat != LUA_OK); 80 lua_assert(stat != LUA_OK);
81 lua_xmove(co, L, 1); /* move error message to the caller */ 81 lua_xmove(co, L, 1); /* move error message to the caller */
82 } 82 }
@@ -172,7 +172,7 @@ static int luaB_close (lua_State *L) {
172 int status = auxstatus(L, co); 172 int status = auxstatus(L, co);
173 switch (status) { 173 switch (status) {
174 case COS_DEAD: case COS_YIELD: { 174 case COS_DEAD: case COS_YIELD: {
175 status = lua_resetthread(co); 175 status = lua_resetthread(co, L);
176 if (status == LUA_OK) { 176 if (status == LUA_OK) {
177 lua_pushboolean(L, 1); 177 lua_pushboolean(L, 1);
178 return 1; 178 return 1;
diff --git a/lstate.c b/lstate.c
index 1ffe1a0f..4b5c1000 100644
--- a/lstate.c
+++ b/lstate.c
@@ -343,9 +343,10 @@ int luaE_resetthread (lua_State *L, int status) {
343} 343}
344 344
345 345
346LUA_API int lua_resetthread (lua_State *L) { 346LUA_API int lua_resetthread (lua_State *L, lua_State *from) {
347 int status; 347 int status;
348 lua_lock(L); 348 lua_lock(L);
349 L->nCcalls = (from) ? getCcalls(from) : 0;
349 status = luaE_resetthread(L, L->status); 350 status = luaE_resetthread(L, L->status);
350 lua_unlock(L); 351 lua_unlock(L);
351 return status; 352 return status;
diff --git a/ltests.c b/ltests.c
index 9a887f98..734a96da 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1533,7 +1533,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
1533 lua_newthread(L1); 1533 lua_newthread(L1);
1534 } 1534 }
1535 else if EQ("resetthread") { 1535 else if EQ("resetthread") {
1536 lua_pushinteger(L1, lua_resetthread(L1)); 1536 lua_pushinteger(L1, lua_resetthread(L1, L));
1537 } 1537 }
1538 else if EQ("newuserdata") { 1538 else if EQ("newuserdata") {
1539 lua_newuserdata(L1, getnum); 1539 lua_newuserdata(L1, getnum);
diff --git a/lua.h b/lua.h
index 219784cc..bfba4d1e 100644
--- a/lua.h
+++ b/lua.h
@@ -153,7 +153,7 @@ extern const char lua_ident[];
153LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); 153LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
154LUA_API void (lua_close) (lua_State *L); 154LUA_API void (lua_close) (lua_State *L);
155LUA_API lua_State *(lua_newthread) (lua_State *L); 155LUA_API lua_State *(lua_newthread) (lua_State *L);
156LUA_API int (lua_resetthread) (lua_State *L); 156LUA_API int (lua_resetthread) (lua_State *L, lua_State *from);
157 157
158LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); 158LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
159 159
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.
4160 4160
4161} 4161}
4162 4162
4163@APIEntry{int lua_resetthread (lua_State *L);| 4163@APIEntry{int lua_resetthread (lua_State *L, lua_State *from);|
4164@apii{0,?,-} 4164@apii{0,?,-}
4165 4165
4166Resets a thread, cleaning its call stack and closing all pending 4166Resets a thread, cleaning its call stack and closing all pending
@@ -4173,6 +4173,11 @@ or an error status otherwise.
4173In case of error, 4173In case of error,
4174leaves the error object on the top of the stack. 4174leaves the error object on the top of the stack.
4175 4175
4176The parameter @id{from} represents the coroutine that is resetting @id{L}.
4177If there is no such coroutine,
4178this parameter can be @id{NULL}.
4179(This parameter was introduced in @N{release 5.4.5}.)
4180
4176} 4181}
4177 4182
4178@APIEntry{int lua_resume (lua_State *L, lua_State *from, int nargs, 4183@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
84end 84end
85 85
86 86
87do -- bug since 5.4.0
88 local count = 0
89 print("chain of 'coroutine.close'")
90 -- create N coroutines forming a list so that each one, when closed,
91 -- closes the previous one. (With a large enough N, previous Lua
92 -- versions crash in this test.)
93 local coro = false
94 for i = 1, 1000 do
95 local previous = coro
96 coro = coroutine.create(function()
97 local cc <close> = setmetatable({}, {__close=function()
98 count = count + 1
99 if previous then
100 assert(coroutine.close(previous))
101 end
102 end})
103 coroutine.yield() -- leaves 'cc' pending to be closed
104 end)
105 assert(coroutine.resume(coro)) -- start it and run until it yields
106 end
107 local st, msg = coroutine.close(coro)
108 assert(not st and string.find(msg, "C stack overflow"))
109 print("final count: ", count)
110end
111
112
87do 113do
88 print("nesting of resuming yielded coroutines") 114 print("nesting of resuming yielded coroutines")
89 local count = 0 115 local count = 0