From: Thierry FOURNIER Date: Fri, 6 Mar 2015 13:05:24 +0000 (+0100) Subject: BUG/MAJOR: lua: some function are not yieldable, the forced yield causes errors X-Git-Tag: v1.6-dev1~55 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cae49c9ee8756da423c1f8cab74ed4a850988be1;p=thirdparty%2Fhaproxy.git BUG/MAJOR: lua: some function are not yieldable, the forced yield causes errors The hook function called each nth Lua instructions just do a yield. Sometimes this yield is not allowed, because some functions are not compatible. The Lua-5.3 permits to known if the yield is avalaible with the function lua_isyieldable(). If the processing is interrupted in non yieldable state, we try to execute a yield asap. The yield will be may available at the end of the non-yieldable currently executed function. So, we require interrupt at the end of the current function. But, Lua cannot yield when its returning from a function, so, we can fix the interrupt hook to 1 instruction, expecting that the function is finnished. During this time, the execution timeout is always checked. --- diff --git a/src/hlua.c b/src/hlua.c index e3769a04db..0923cfd0a4 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -644,7 +644,36 @@ static int hlua_ctx_renew(struct hlua *lua, int keep_msg) void hlua_hook(lua_State *L, lua_Debug *ar) { - hlua_yieldk(L, 0, 0, NULL, TICK_ETERNITY, HLUA_CTRLYIELD); + struct hlua *hlua = hlua_gethlua(L); + + /* Lua cannot yield when its returning from a function, + * so, we can fix the interrupt hook to 1 instruction, + * expecting that the function is finnished. + */ + if (lua_gethookmask(L) & LUA_MASKRET) { + lua_sethook(hlua->T, hlua_hook, LUA_MASKCOUNT, 1); + return; + } + + /* restore the interrupt condition. */ + lua_sethook(hlua->T, hlua_hook, LUA_MASKCOUNT, hlua_nb_instruction); + + /* If we interrupt the Lua processing in yieldable state, we yield. + * If the state is not yieldable, trying yield causes an error. + */ + if (lua_isyieldable(L)) + WILL_LJMP(hlua_yieldk(L, 0, 0, NULL, TICK_ETERNITY, HLUA_CTRLYIELD)); + + /* If we cannot yield, check the timeout. */ + if (tick_is_expired(hlua->expire, now_ms)) { + lua_pushfstring(L, "execution timeout"); + WILL_LJMP(lua_error(L)); + } + + /* Try to interrupt the process at the end of the current + * unyieldable function. + */ + lua_sethook(hlua->T, hlua_hook, LUA_MASKRET|LUA_MASKCOUNT, hlua_nb_instruction); } /* This function start or resumes the Lua stack execution. If the flag