mirror of https://github.com/rusefi/lua.git
Bug: stack overflow with nesting of coroutine.close
This commit is contained in:
parent
b85816b9a8
commit
1e64c1391f
|
@ -76,7 +76,7 @@ static int luaB_auxwrap (lua_State *L) {
|
||||||
if (l_unlikely(r < 0)) { /* error? */
|
if (l_unlikely(r < 0)) { /* error? */
|
||||||
int stat = lua_status(co);
|
int stat = lua_status(co);
|
||||||
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
|
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_assert(stat != LUA_OK);
|
||||||
lua_xmove(co, L, 1); /* move error message to the caller */
|
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);
|
int status = auxstatus(L, co);
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case COS_DEAD: case COS_YIELD: {
|
case COS_DEAD: case COS_YIELD: {
|
||||||
status = lua_resetthread(co);
|
status = lua_resetthread(co, L);
|
||||||
if (status == LUA_OK) {
|
if (status == LUA_OK) {
|
||||||
lua_pushboolean(L, 1);
|
lua_pushboolean(L, 1);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
3
lstate.c
3
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;
|
int status;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
|
L->nCcalls = (from) ? getCcalls(from) : 0;
|
||||||
status = luaE_resetthread(L, L->status);
|
status = luaE_resetthread(L, L->status);
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
return status;
|
return status;
|
||||||
|
|
2
ltests.c
2
ltests.c
|
@ -1533,7 +1533,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
|
||||||
lua_newthread(L1);
|
lua_newthread(L1);
|
||||||
}
|
}
|
||||||
else if EQ("resetthread") {
|
else if EQ("resetthread") {
|
||||||
lua_pushinteger(L1, lua_resetthread(L1));
|
lua_pushinteger(L1, lua_resetthread(L1, L));
|
||||||
}
|
}
|
||||||
else if EQ("newuserdata") {
|
else if EQ("newuserdata") {
|
||||||
lua_newuserdata(L1, getnum);
|
lua_newuserdata(L1, getnum);
|
||||||
|
|
2
lua.h
2
lua.h
|
@ -153,7 +153,7 @@ extern const char lua_ident[];
|
||||||
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
|
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
|
||||||
LUA_API void (lua_close) (lua_State *L);
|
LUA_API void (lua_close) (lua_State *L);
|
||||||
LUA_API lua_State *(lua_newthread) (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);
|
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
|
||||||
|
|
||||||
|
|
|
@ -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,?,-}
|
@apii{0,?,-}
|
||||||
|
|
||||||
Resets a thread, cleaning its call stack and closing all pending
|
Resets a thread, cleaning its call stack and closing all pending
|
||||||
|
@ -4173,6 +4173,11 @@ or an error status otherwise.
|
||||||
In case of error,
|
In case of error,
|
||||||
leaves the error object on the top of the stack.
|
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,
|
@APIEntry{int lua_resume (lua_State *L, lua_State *from, int nargs,
|
||||||
|
|
|
@ -84,6 +84,32 @@ do -- bug in 5.4.0
|
||||||
end
|
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
|
do
|
||||||
print("nesting of resuming yielded coroutines")
|
print("nesting of resuming yielded coroutines")
|
||||||
local count = 0
|
local count = 0
|
||||||
|
|
Loading…
Reference in New Issue