From: Christopher Faulet Date: Thu, 5 Aug 2021 09:58:37 +0000 (+0200) Subject: BUG/MINOR: lua: Yield in channel functions only if lua context can yield X-Git-Tag: v2.5-dev4~36 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2e60aa4dee4a07a8688ba456aa7036b85340cfdd;p=thirdparty%2Fhaproxy.git BUG/MINOR: lua: Yield in channel functions only if lua context can yield When a script is executed, it is not always allowed to yield. Lua sample fetches and converters cannot yield. For lua actions, it depends on the context. When called from tcp content ruleset, an action may yield until the expiration of the inspect-delay timeout. From http rulesets, yield is not possible. Thus, when channel functions (dup, get, append, send...) are called, instead of yielding when it is not allowed and triggering an error, we just give up. In this case, some functions do nothing (dup, append...), some others just interrupt the in-progress job (send, forward...). But, because these functions don't yield anymore when it is not allowed, the script regains the control and can continue its execution. This patch depends on "MINOR: lua: Add a flag on lua context to know the yield capability at run time". Both may be backported in all stable versions. However, because nobody notice this bug till now, it is probably not necessary, excepted if someone ask for it. --- diff --git a/src/hlua.c b/src/hlua.c index 0de63422dc..22c6a03c09 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -2931,12 +2931,12 @@ static inline int _hlua_channel_dup(struct channel *chn, lua_State *L) luaL_Buffer b; ret = ci_getblk_nc(chn, &blk1, &len1, &blk2, &len2); - if (unlikely(ret == 0)) + if (unlikely(ret <= 0)) { + if (ret < 0 || HLUA_CANT_YIELD(hlua_gethlua(L))) { + lua_pushnil(L); + return -1; + } return 0; - - if (unlikely(ret < 0)) { - lua_pushnil(L); - return -1; } luaL_buffinit(L, &b); @@ -3037,8 +3037,13 @@ __LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KCont } ret = ci_getline_nc(chn, &blk1, &len1, &blk2, &len2); - if (ret == 0) + if (ret == 0) { + if (HLUA_CANT_YIELD(hlua_gethlua(L))) { + _hlua_channel_dup(chn, L); + return 1; + } MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_getline_yield, TICK_ETERNITY, 0)); + } if (ret == -1) { lua_pushnil(L); @@ -3099,11 +3104,11 @@ __LJMP static int hlua_channel_append_yield(lua_State *L, int status, lua_KConte max = len - l; ret = ci_putblk(chn, str + l, max); - if (ret == -2 || ret == -3) { - lua_pushinteger(L, -1); - return 1; - } - if (ret == -1) { + if (ret < 0) { + if (ret == -2 || ret == -3 || HLUA_CANT_YIELD(hlua_gethlua(L))) { + lua_pushinteger(L, -1); + return 1; + } chn->flags |= CF_WAKE_WRITE; MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_append_yield, TICK_ETERNITY, 0)); } @@ -3111,16 +3116,16 @@ __LJMP static int hlua_channel_append_yield(lua_State *L, int status, lua_KConte lua_pop(L, 1); lua_pushinteger(L, l); - max = channel_recv_limit(chn) - b_data(&chn->buf); - if (max == 0 && co_data(chn) == 0) { - /* There are no space available, and the output buffer is empty. - * in this case, we cannot add more data, so we cannot yield, - * we return the amount of copied data. + if (l < len) { + /* If there are no space available, and the output buffer is + * empty, we cannot add more data, so we cannot yield, we return + * the amount of copied data. */ - return 1; - } - if (l < len) + max = channel_recv_limit(chn) - b_data(&chn->buf); + if ((max == 0 && co_data(chn) == 0) || HLUA_CANT_YIELD(hlua_gethlua(L))) + return 1; MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_append_yield, TICK_ETERNITY, 0)); + } return 1; } @@ -3200,6 +3205,8 @@ __LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext * the request buffer if its not required. */ if (chn->buf.size == 0) { + if (HLUA_CANT_YIELD(hlua_gethlua(L))) + return 1; si_rx_buff_blk(chn_prod(chn)); MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0)); } @@ -3240,15 +3247,15 @@ __LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext lua_pop(L, 1); lua_pushinteger(L, l); - /* If there is no space available, and the output buffer is empty. - * in this case, we cannot add more data, so we cannot yield, - * we return the amount of copied data. - */ - max = b_room(&chn->buf); - if (max == 0 && co_data(chn) == 0) - return 1; - if (l < len) { + /* If there is no space available, and the output buffer is empty. + * in this case, we cannot add more data, so we cannot yield, + * we return the amount of copied data. + */ + max = b_room(&chn->buf); + if ((max == 0 && co_data(chn) == 0) || HLUA_CANT_YIELD(hlua_gethlua(L))) + return 1; + /* If we are waiting for space in the response buffer, we * must set the flag WAKERESWR. This flag required the task * wake up if any activity is detected on the response buffer. @@ -3319,7 +3326,7 @@ __LJMP static int hlua_channel_forward_yield(lua_State *L, int status, lua_KCont /* The the input channel or the output channel are closed, we * must return the amount of data forwarded. */ - if (channel_input_closed(chn) || channel_output_closed(chn)) + if (channel_input_closed(chn) || channel_output_closed(chn) || HLUA_CANT_YIELD(hlua_gethlua(L))) return 1; /* If we are waiting for space data in the response buffer, we