Skip to content

Commit bfbff37

Browse files
committed
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.
1 parent 74d9905 commit bfbff37

File tree

3 files changed

+47
-5
lines changed

3 files changed

+47
-5
lines changed

lcorolib.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ static int luaB_auxwrap (lua_State *L) {
7878
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
7979
stat = lua_resetthread(co); /* close its tbc variables */
8080
lua_assert(stat != LUA_OK);
81-
lua_xmove(co, L, 1); /* copy error message */
81+
lua_xmove(co, L, 1); /* move error message to the caller */
8282
}
8383
if (stat != LUA_ERRMEM && /* not a memory error and ... */
8484
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
@@ -179,7 +179,7 @@ static int luaB_close (lua_State *L) {
179179
}
180180
else {
181181
lua_pushboolean(L, 0);
182-
lua_xmove(co, L, 1); /* copy error message */
182+
lua_xmove(co, L, 1); /* move error message */
183183
return 2;
184184
}
185185
}

lstate.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ void luaE_checkcstack (lua_State *L) {
166166
if (getCcalls(L) == LUAI_MAXCCALLS)
167167
luaG_runerror(L, "C stack overflow");
168168
else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
169-
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
169+
luaD_throw(L, LUA_ERRERR); /* error while handling stack error */
170170
}
171171

172172

@@ -330,13 +330,13 @@ int luaE_resetthread (lua_State *L, int status) {
330330
ci->callstatus = CIST_C;
331331
if (status == LUA_YIELD)
332332
status = LUA_OK;
333+
L->status = LUA_OK; /* so it can run __close metamethods */
333334
status = luaD_closeprotected(L, 1, status);
334335
if (status != LUA_OK) /* errors? */
335336
luaD_seterrorobj(L, status, L->stack + 1);
336337
else
337338
L->top = L->stack + 1;
338339
ci->top = L->top + LUA_MINSTACK;
339-
L->status = cast_byte(status);
340340
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
341341
return status;
342342
}

testes/coroutine.lua

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ do
136136
assert(coroutine.status(co) == "dead")
137137
local st, msg = coroutine.close(co)
138138
assert(st and msg == nil)
139+
-- also ok to close it again
140+
st, msg = coroutine.close(co)
141+
assert(st and msg == nil)
142+
139143

140144
-- cannot close the running coroutine
141145
local st, msg = pcall(coroutine.close, coroutine.running())
@@ -149,6 +153,22 @@ do
149153
assert(not st and string.find(msg, "normal"))
150154
end))()
151155

156+
-- cannot close a coroutine while closing it
157+
do
158+
local co
159+
co = coroutine.create(
160+
function()
161+
local x <close> = func2close(function()
162+
coroutine.close(co) -- try to close it again
163+
end)
164+
coroutine.yield(20)
165+
end)
166+
local st, msg = coroutine.resume(co)
167+
assert(st and msg == 20)
168+
st, msg = coroutine.close(co)
169+
assert(not st and string.find(msg, "running coroutine"))
170+
end
171+
152172
-- to-be-closed variables in coroutines
153173
local X
154174

@@ -158,6 +178,9 @@ do
158178
assert(not st and msg == 100)
159179
st, msg = coroutine.close(co)
160180
assert(not st and msg == 100)
181+
-- after closing, no more errors
182+
st, msg = coroutine.close(co)
183+
assert(st and msg == nil)
161184

162185
co = coroutine.create(function ()
163186
local x <close> = func2close(function (self, err)
@@ -189,6 +212,9 @@ do
189212
local st, msg = coroutine.close(co)
190213
assert(st == false and coroutine.status(co) == "dead" and msg == 200)
191214
assert(x == 200)
215+
-- after closing, no more errors
216+
st, msg = coroutine.close(co)
217+
assert(st and msg == nil)
192218
end
193219

194220
do
@@ -419,14 +445,30 @@ do
419445

420446
local X = false
421447
A = coroutine.wrap(function()
422-
local _ <close> = setmetatable({}, {__close = function () X = true end})
448+
local _ <close> = func2close(function () X = true end)
423449
return pcall(A, 1)
424450
end)
425451
st, res = A()
426452
assert(not st and string.find(res, "non%-suspended") and X == true)
427453
end
428454

429455

456+
-- bug in 5.4.1
457+
do
458+
-- coroutine ran close metamethods with invalid status during a
459+
-- reset.
460+
local co
461+
co = coroutine.wrap(function()
462+
local x <close> = func2close(function() return pcall(co) end)
463+
error(111)
464+
end)
465+
local st, errobj = pcall(co)
466+
assert(not st and errobj == 111)
467+
st, errobj = pcall(co)
468+
assert(not st and string.find(errobj, "dead coroutine"))
469+
end
470+
471+
430472
-- attempt to resume 'normal' coroutine
431473
local co1, co2
432474
co1 = coroutine.create(function () return co2() end)

0 commit comments

Comments
 (0)