From 6140507ba7747c9bf9d3f97ecb99922be67b3406 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Wed, 16 Jan 2019 16:14:30 +0100 Subject: [PATCH] unix,stream: fix zero byte writes Fixes a regression where a write request to write a zero byte buffer would never complete. Refs: https://github.com/libuv/libuv/pull/2097 Refs: https://github.com/libuv/libuv/issues/2134 PR-URL: https://github.com/libuv/libuv/pull/2149 Reviewed-By: Ben Noordhuis --- src/unix/stream.c | 6 +++--- test/run-tests.c | 5 +++++ test/test-ipc.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++ test/test-list.h | 2 ++ 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/unix/stream.c b/src/unix/stream.c index a75ba157679..7e4d5fc7ffd 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -745,13 +745,13 @@ static int uv__write_req_update(uv_stream_t* stream, buf = req->bufs + req->write_index; - while (n > 0) { + do { len = n < buf->len ? n : buf->len; buf->base += len; buf->len -= len; buf += (buf->len == 0); /* Advance to next buffer if this one is empty. */ n -= len; - } + } while (n > 0); req->write_index = buf - req->bufs; @@ -897,7 +897,7 @@ static void uv__write(uv_stream_t* stream) { goto error; } - if (n > 0 && uv__write_req_update(stream, req, n)) { + if (n >= 0 && uv__write_req_update(stream, req, n)) { uv__write_req_finish(req); return; /* TODO(bnoordhuis) Start trying to write the next request. */ } diff --git a/test/run-tests.c b/test/run-tests.c index 2a699f46dcb..eba28ecb9aa 100644 --- a/test/run-tests.c +++ b/test/run-tests.c @@ -42,6 +42,7 @@ int ipc_helper_tcp_connection(void); int ipc_helper_closed_handle(void); int ipc_send_recv_helper(void); int ipc_helper_bind_twice(void); +int ipc_helper_send_zero(void); int stdio_over_pipes_helper(void); int spawn_stdin_stdout(void); int spawn_tcp_server_helper(void); @@ -104,6 +105,10 @@ static int maybe_run_test(int argc, char **argv) { return ipc_helper_bind_twice(); } + if (strcmp(argv[1], "ipc_helper_send_zero") == 0) { + return ipc_helper_send_zero(); + } + if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) { return stdio_over_pipes_helper(); } diff --git a/test/test-ipc.c b/test/test-ipc.c index 26cf1df010f..88d04ba143c 100644 --- a/test/test-ipc.c +++ b/test/test-ipc.c @@ -47,6 +47,7 @@ static int tcp_conn_read_cb_called; static int tcp_conn_write_cb_called; static int closed_handle_data_read; static int closed_handle_write; +static int send_zero_write; typedef struct { uv_connect_t conn_req; @@ -431,6 +432,14 @@ static void on_read_closed_handle(uv_stream_t* handle, #endif +static void on_read_send_zero(uv_stream_t* handle, + ssize_t nread, + const uv_buf_t* buf) { + ASSERT(nread == 0 || nread == UV_EOF); + free(buf->base); +} + + static int run_ipc_test(const char* helper, uv_read_cb read_cb) { uv_process_t process; int r; @@ -555,6 +564,13 @@ TEST_IMPL(ipc_listen_after_bind_twice) { } #endif +TEST_IMPL(ipc_send_zero) { + int r; + r = run_ipc_test("ipc_helper_send_zero", on_read_send_zero); + ASSERT(r == 0); + return 0; +} + /* Everything here runs in a child process. */ @@ -598,6 +614,11 @@ static void closed_handle_write_cb(uv_write_t* req, int status) { } +static void send_zero_write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); + send_zero_write++; +} + static void on_tcp_child_process_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { @@ -919,3 +940,35 @@ int ipc_helper_bind_twice(void) { MAKE_VALGRIND_HAPPY(); return 0; } + +int ipc_helper_send_zero(void) { + int r; + uv_buf_t zero_buf; + + zero_buf = uv_buf_init(0, 0); + + r = uv_pipe_init(uv_default_loop(), &channel, 0); + ASSERT(r == 0); + + uv_pipe_open(&channel, 0); + + ASSERT(1 == uv_is_readable((uv_stream_t*) &channel)); + ASSERT(1 == uv_is_writable((uv_stream_t*) &channel)); + ASSERT(0 == uv_is_closing((uv_handle_t*) &channel)); + + r = uv_write(&write_req, + (uv_stream_t*)&channel, + &zero_buf, + 1, + send_zero_write_cb); + + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(send_zero_write == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} \ No newline at end of file diff --git a/test/test-list.h b/test/test-list.h index 61208a0c516..53372c90f76 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -69,6 +69,7 @@ TEST_DECLARE (ipc_send_recv_pipe_inprocess) TEST_DECLARE (ipc_send_recv_tcp) TEST_DECLARE (ipc_send_recv_tcp_inprocess) TEST_DECLARE (ipc_tcp_connection) +TEST_DECLARE (ipc_send_zero) #ifndef _WIN32 TEST_DECLARE (ipc_closed_handle) #endif @@ -515,6 +516,7 @@ TASK_LIST_START TEST_ENTRY (ipc_send_recv_tcp) TEST_ENTRY (ipc_send_recv_tcp_inprocess) TEST_ENTRY (ipc_tcp_connection) + TEST_ENTRY (ipc_send_zero) #ifndef _WIN32 TEST_ENTRY (ipc_closed_handle) #endif