mirror of https://github.com/rusefi/lua.git
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.
This commit is contained in:
parent
74d99057a5
commit
bfbff3703e
|
@ -78,7 +78,7 @@ static int luaB_auxwrap (lua_State *L) {
|
||||||
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); /* close its tbc variables */
|
||||||
lua_assert(stat != LUA_OK);
|
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 ... */
|
if (stat != LUA_ERRMEM && /* not a memory error and ... */
|
||||||
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
|
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
|
||||||
|
@ -179,7 +179,7 @@ static int luaB_close (lua_State *L) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lua_pushboolean(L, 0);
|
lua_pushboolean(L, 0);
|
||||||
lua_xmove(co, L, 1); /* copy error message */
|
lua_xmove(co, L, 1); /* move error message */
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
lstate.c
4
lstate.c
|
@ -166,7 +166,7 @@ void luaE_checkcstack (lua_State *L) {
|
||||||
if (getCcalls(L) == LUAI_MAXCCALLS)
|
if (getCcalls(L) == LUAI_MAXCCALLS)
|
||||||
luaG_runerror(L, "C stack overflow");
|
luaG_runerror(L, "C stack overflow");
|
||||||
else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
|
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;
|
ci->callstatus = CIST_C;
|
||||||
if (status == LUA_YIELD)
|
if (status == LUA_YIELD)
|
||||||
status = LUA_OK;
|
status = LUA_OK;
|
||||||
|
L->status = LUA_OK; /* so it can run __close metamethods */
|
||||||
status = luaD_closeprotected(L, 1, status);
|
status = luaD_closeprotected(L, 1, status);
|
||||||
if (status != LUA_OK) /* errors? */
|
if (status != LUA_OK) /* errors? */
|
||||||
luaD_seterrorobj(L, status, L->stack + 1);
|
luaD_seterrorobj(L, status, L->stack + 1);
|
||||||
else
|
else
|
||||||
L->top = L->stack + 1;
|
L->top = L->stack + 1;
|
||||||
ci->top = L->top + LUA_MINSTACK;
|
ci->top = L->top + LUA_MINSTACK;
|
||||||
L->status = cast_byte(status);
|
|
||||||
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
|
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,6 +136,10 @@ do
|
||||||
assert(coroutine.status(co) == "dead")
|
assert(coroutine.status(co) == "dead")
|
||||||
local st, msg = coroutine.close(co)
|
local st, msg = coroutine.close(co)
|
||||||
assert(st and msg == nil)
|
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
|
-- cannot close the running coroutine
|
||||||
local st, msg = pcall(coroutine.close, coroutine.running())
|
local st, msg = pcall(coroutine.close, coroutine.running())
|
||||||
|
@ -149,6 +153,22 @@ do
|
||||||
assert(not st and string.find(msg, "normal"))
|
assert(not st and string.find(msg, "normal"))
|
||||||
end))()
|
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
|
-- to-be-closed variables in coroutines
|
||||||
local X
|
local X
|
||||||
|
|
||||||
|
@ -158,6 +178,9 @@ do
|
||||||
assert(not st and msg == 100)
|
assert(not st and msg == 100)
|
||||||
st, msg = coroutine.close(co)
|
st, msg = coroutine.close(co)
|
||||||
assert(not st and msg == 100)
|
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 ()
|
co = coroutine.create(function ()
|
||||||
local x <close> = func2close(function (self, err)
|
local x <close> = func2close(function (self, err)
|
||||||
|
@ -189,6 +212,9 @@ do
|
||||||
local st, msg = coroutine.close(co)
|
local st, msg = coroutine.close(co)
|
||||||
assert(st == false and coroutine.status(co) == "dead" and msg == 200)
|
assert(st == false and coroutine.status(co) == "dead" and msg == 200)
|
||||||
assert(x == 200)
|
assert(x == 200)
|
||||||
|
-- after closing, no more errors
|
||||||
|
st, msg = coroutine.close(co)
|
||||||
|
assert(st and msg == nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
|
@ -419,7 +445,7 @@ do
|
||||||
|
|
||||||
local X = false
|
local X = false
|
||||||
A = coroutine.wrap(function()
|
A = coroutine.wrap(function()
|
||||||
local _ <close> = setmetatable({}, {__close = function () X = true end})
|
local _ <close> = func2close(function () X = true end)
|
||||||
return pcall(A, 1)
|
return pcall(A, 1)
|
||||||
end)
|
end)
|
||||||
st, res = A()
|
st, res = A()
|
||||||
|
@ -427,6 +453,22 @@ do
|
||||||
end
|
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
|
-- attempt to resume 'normal' coroutine
|
||||||
local co1, co2
|
local co1, co2
|
||||||
co1 = coroutine.create(function () return co2() end)
|
co1 = coroutine.create(function () return co2() end)
|
||||||
|
|
Loading…
Reference in New Issue