lua-users home
lua-l archive

Re: Bug: non-error unwind of previously yielded pcall doesn't restore errfunc.

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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
> 

AltStyle によって変換されたページ (->オリジナル) /