Bug: Yielding in a hook stops in the wrong instruction

Yielding in a hook must decrease the program counter, because it already
counted an instruction that, in the end, was not executed. However,
that decrement should be done only when about to restart the thread.
Otherwise, inspecting the thread with the debug library shows it one
instruction behind of where it really is.
This commit is contained in:
Roberto Ierusalimschy 2024-01-11 13:44:16 -03:00
parent 5853c37a83
commit e288c5a918
3 changed files with 11 additions and 6 deletions

View File

@ -925,12 +925,12 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
}
pc++; /* reference is always next instruction */
ci->u.l.savedpc = pc; /* save 'pc' */
counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
counthook = (mask & LUA_MASKCOUNT) && (--L->hookcount == 0);
if (counthook)
resethookcount(L); /* reset count */
else if (!(mask & LUA_MASKLINE))
return 1; /* no line hook and count != 0; nothing to be done now */
if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
if (ci->callstatus & CIST_HOOKYIELD) { /* hook yielded last time? */
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
return 1; /* do not call hook again (VM yielded, so it did not move) */
}
@ -952,7 +952,6 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
if (L->status == LUA_YIELD) { /* did hook yield? */
if (counthook)
L->hookcount = 1; /* undo decrement to zero */
ci->u.l.savedpc--; /* undo increment (resume will increment it again) */
ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */
luaD_throw(L, LUA_YIELD);
}

4
ldo.c
View File

@ -792,6 +792,10 @@ static void resume (lua_State *L, void *ud) {
lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */
if (isLua(ci)) { /* yielded inside a hook? */
/* undo increment made by 'luaG_traceexec': instruction was not
executed yet */
lua_assert(ci->callstatus & CIST_HOOKYIELD);
ci->u.l.savedpc--;
L->top.p = firstArg; /* discard arguments */
luaV_execute(L, ci); /* just continue running Lua code */
}

View File

@ -610,18 +610,20 @@ else
-- (bug in 5.2/5.3)
c = coroutine.create(function (a, ...)
T.sethook("yield 0", "l") -- will yield on next two lines
assert(a == 10)
local b = a
return ...
end)
assert(coroutine.resume(c, 1, 2, 3)) -- start coroutine
local n,v = debug.getlocal(c, 0, 1) -- check its local
assert(n == "a" and v == 1)
assert(n == "a" and v == 1 and debug.getlocal(c, 0, 2) ~= "b")
assert(debug.setlocal(c, 0, 1, 10)) -- test 'setlocal'
local t = debug.getinfo(c, 0) -- test 'getinfo'
assert(t.currentline == t.linedefined + 1)
assert(t.currentline == t.linedefined + 2)
assert(not debug.getinfo(c, 1)) -- no other level
assert(coroutine.resume(c)) -- run next line
local n,v = debug.getlocal(c, 0, 2) -- check next local
assert(n == "b" and v == 10)
v = {coroutine.resume(c)} -- finish coroutine
assert(v[1] == true and v[2] == 2 and v[3] == 3 and v[4] == undef)
assert(not coroutine.resume(c))