Hi Tim,

Thanks for the patch. Good catch !
Willy, you can apply it.

Thierry

> On 4 Jan 2018, at 19:32, Tim Duesterhus <t...@bastelstu.be> wrote:
> 
> The default value of the pattern in `Socket.receive` is `*l` according
> to the documentation and in the `socket.tcp.receive` method of Lua.
> 
> The default value of `wanted` in `int hlua_socket_receive(struct lua_State *)`
> reflects this requirement, but the function fails to ensure this
> nonetheless:
> 
> If no parameter is given the top of the Lua stack will have the index 1.
> `lua_pushinteger(L, wanted);` then pushes the default value onto the stack
> (with index 2).
> The following `lua_replace(L, 2);` then pops the top index (2) and tries to
> replace the index 2 with it.
> I am not sure why exactly that happens (possibly, because one cannot replace
> non-existent stack indicies), but this causes the stack index to be lost.
> 
> `hlua_socket_receive_yield` then tries to read the stack index 2, to
> determine what to read and get the value `0`, instead of the correct
> HLSR_READ_LINE, thus taking the wrong branch.
> 
> Fix this by ensuring that the top of the stack is not replaced by itself.
> 
> This bug was introduced in commit 7e7ac32dad1e15c19152d37aaf9ea6b3f00a7226
> (which is the very first commit adding the Socket class to Lua). This
> bugfix should be backported to every branch containing that commit:
> - 1.6
> - 1.7
> - 1.8
> 
> A test case for this bug is as follows:
> 
> The 'Test' response header will contain an HTTP status line with the
> patch applied and will be empty without the patch applied. Replacing
> the `sock:receive()` with `sock:receive("*l")` will cause the status
> line to appear with and without the patch
> 
> http.lua:
>  core.register_action("bug", { "http-req" }, function(txn)
>       local sock = core.tcp()
>       sock:settimeout(60)
>       sock:connect("127.0.0.1:80")
>       sock:send("GET / HTTP/1.0\r\n\r\n")
>       response = sock:receive()
>       sock:close()
>       txn:set_var("txn.foo", response)
>  end)
> 
> haproxy.cfg (bits omitted for brevity):
>  global
>       lua-load /scratch/haproxy/http.lua
> 
>  frontend fe
>       bind 127.0.0.1:8080
>       http-request lua.bug
>       http-response set-header Test %[var(txn.foo)]
> 
>       default_backend be
> 
>  backend be
>       server s 127.0.0.1:80
> ---
> src/hlua.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/src/hlua.c b/src/hlua.c
> index abd096d03..285d25589 100644
> --- a/src/hlua.c
> +++ b/src/hlua.c
> @@ -1869,7 +1869,10 @@ __LJMP static int hlua_socket_receive(struct lua_State 
> *L)
> 
>       /* Set pattern. */
>       lua_pushinteger(L, wanted);
> -     lua_replace(L, 2);
> +
> +     /* Check if we would replace the top by itself. */
> +     if (lua_gettop(L) != 2)
> +             lua_replace(L, 2);
> 
>       /* init bufffer, and fiil it wih prefix. */
>       luaL_buffinit(L, &socket->b);
> -- 
> 2.15.1
> 


Reply via email to