[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Bug: non-error unwind of previously yielded pcall doesn't restore errfunc.
- From: Alexander Gavrilov <angavrilov@...>
- Date: Sun, 15 Jul 2012 11:26:43 +0400
Hi,
I wonder if the mail below perhaps went unnoticed - there was
a lot of other mail on the same day :)
So that this mail contains some useful content too, here are two
things that I have found to be very simple to do when accessing
internals, but difficult to reproduce via the current C API:
1) Determine if two threads belong to the same shared interpreter state:
bool is_same_state(lua_State *L1, lua_State *L2) { return L1->l_G == L2->l_G; }
I used this for some assertions. I believe the only way around it
involves using the registry, and thus writing to the stack of at
least one of the states. This way is purely symmetrical, read-only
and fast.
2) Determine if the current state is yieldable:
bool is_yieldable(lua_State *L) { return L->nny == 0; }
In lua code for 5.2 this can be easily worked around by doing
pcall(coroutine.yield), but reproducing it in C is rather cumbersome.
I wanted this to provide a fallback to a non-yielding blocking
implementation.
Alexander
On Monday 18 June 2012 12:29:24 Alexander Gavrilov wrote:
> Hi,
>
> I've noticed one more bug with pcalls in coroutines: they don't
> always restore the previous value of errfunc on exit. Specifically,
> if a yield happens through a chain of pcalls, and then no errors
> are thrown after resume, the errfunc value will remain the same as
> at the time of yield.
>
> Example:
>
> function errfunc(x)
> return 'errfunc'
> end
>
> function test(do_yield)
> print('yielding:',do_yield)
> pcall(function() -- this pcall sets errfunc back to none
> if do_yield then
> coroutine.yield() -- stops errfunc from being restored
> end
> end)
> error('fail!')
> end
>
> coro = coroutine.wrap(function()
> print(xpcall(test, errfunc, false))
> print(xpcall(test, errfunc, true))
> print(xpcall(test, errfunc, false))
> end)
>
> coro()
> coro()
>
> Output:
>
> yielding: false
> false errfunc
> yielding: true
> false input:13: fail!
> yielding: false
> false errfunc
>
> This appears to fix it:
>
> @@ -402,6 +402,9 @@ static void finishCcall (lua_State *L) {
> int n;
> lua_assert(ci->u.c.k != NULL); /* must have a continuation */
> lua_assert(L->nny == 0);
> + /* finish 'lua_pcallk' */
> + if (ci->callstatus & CIST_YPCALL)
> + L->errfunc = ci->u.c.old_errfunc;
> /* finish 'lua_callk' */
> adjustresults(L, ci->nresults);
> /* call continuation function */
>
> Alexander
>