win,pipe: ensure req->event_handle is defined

Previously, this field was being used uninitialized, leading to the
uv_write call returning failure. This only happens in the rare fallback
path where UV_HANDLE_EMULATE_IOCP is set, meaning that the OVERLAPPED
opened pipe already was associated with an IOCP.

Fixes: https://github.com/libuv/libuv/issues/629
PR-URL: https://github.com/libuv/libuv/pull/2620
Reviewed-By: Saúl Ibarra Corretgé <s@saghul.net>
This commit is contained in:
Elliot Saba 2017-05-30 22:29:37 -07:00 committed by Saúl Ibarra Corretgé
parent a5da270f78
commit 56fc3de48c
3 changed files with 101 additions and 48 deletions

View File

@ -1194,8 +1194,16 @@ int uv_pipe_read_start(uv_pipe_t* handle,
/* If reading was stopped and then started again, there could still be a read
* request pending. */
if (!(handle->flags & UV_HANDLE_READ_PENDING))
if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
handle->read_req.event_handle == NULL) {
handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL);
if (handle->read_req.event_handle == NULL) {
uv_fatal_error(GetLastError(), "CreateEvent");
}
}
uv_pipe_queue_read(loop, handle);
}
return 0;
}

View File

@ -60,6 +60,7 @@ TEST_DECLARE (tty_composing_character)
TEST_DECLARE (tty_file)
TEST_DECLARE (tty_pty)
TEST_DECLARE (stdio_over_pipes)
TEST_DECLARE (stdio_emulate_iocp)
TEST_DECLARE (ip6_pton)
TEST_DECLARE (connect_unspecified)
TEST_DECLARE (ipc_heavy_traffic_deadlock_bug)
@ -550,6 +551,7 @@ TASK_LIST_START
TEST_ENTRY (tty_file)
TEST_ENTRY (tty_pty)
TEST_ENTRY (stdio_over_pipes)
TEST_ENTRY (stdio_emulate_iocp)
TEST_ENTRY (ip6_pton)
TEST_ENTRY (connect_unspecified)
TEST_ENTRY (ipc_heavy_traffic_deadlock_bug)

View File

@ -94,7 +94,7 @@ static void after_write(uv_write_t* req, int status) {
}
static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* rdbuf) {
static void on_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* rdbuf) {
uv_write_t* req;
uv_buf_t wrbuf;
int r;
@ -103,11 +103,11 @@ static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* rdbuf) {
if (nread > 0) {
output_used += nread;
if (output_used == 12) {
if (output_used % 12 == 0) {
ASSERT(memcmp("hello world\n", output, 12) == 0);
wrbuf = uv_buf_init(output, output_used);
wrbuf = uv_buf_init(output, 12);
req = malloc(sizeof(*req));
r = uv_write(req, (uv_stream_t*)&in, &wrbuf, 1, after_write);
r = uv_write(req, (uv_stream_t*) &in, &wrbuf, 1, after_write);
ASSERT(r == 0);
}
}
@ -116,10 +116,10 @@ static void on_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* rdbuf) {
}
TEST_IMPL(stdio_over_pipes) {
static void test_stdio_over_pipes(int overlapped) {
int r;
uv_process_t process;
uv_stdio_container_t stdio[2];
uv_stdio_container_t stdio[3];
loop = uv_default_loop();
@ -129,11 +129,15 @@ TEST_IMPL(stdio_over_pipes) {
uv_pipe_init(loop, &in, 0);
options.stdio = stdio;
options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE;
options.stdio[0].data.stream = (uv_stream_t*)&in;
options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE;
options.stdio[1].data.stream = (uv_stream_t*)&out;
options.stdio_count = 2;
options.stdio[0].flags = UV_CREATE_PIPE | UV_READABLE_PIPE |
(overlapped ? UV_OVERLAPPED_PIPE : 0);
options.stdio[0].data.stream = (uv_stream_t*) &in;
options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE |
(overlapped ? UV_OVERLAPPED_PIPE : 0);
options.stdio[1].data.stream = (uv_stream_t*) &out;
options.stdio[2].flags = UV_INHERIT_FD;
options.stdio[2].data.fd = 2;
options.stdio_count = 3;
r = uv_spawn(loop, &process, &options);
ASSERT(r == 0);
@ -145,13 +149,22 @@ TEST_IMPL(stdio_over_pipes) {
ASSERT(r == 0);
ASSERT(on_read_cb_called > 1);
ASSERT(after_write_cb_called == 1);
ASSERT(after_write_cb_called == 2);
ASSERT(exit_cb_called == 1);
ASSERT(close_cb_called == 3);
ASSERT(memcmp("hello world\n", output, 12) == 0);
ASSERT(output_used == 12);
ASSERT(memcmp("hello world\nhello world\n", output, 24) == 0);
ASSERT(output_used == 24);
MAKE_VALGRIND_HAPPY();
}
TEST_IMPL(stdio_over_pipes) {
test_stdio_over_pipes(0);
return 0;
}
TEST_IMPL(stdio_emulate_iocp) {
test_stdio_over_pipes(1);
return 0;
}
@ -160,18 +173,19 @@ TEST_IMPL(stdio_over_pipes) {
static int on_pipe_read_called;
static int after_write_called;
static uv_pipe_t stdin_pipe;
static uv_pipe_t stdout_pipe;
static uv_pipe_t stdin_pipe1;
static uv_pipe_t stdout_pipe1;
static uv_pipe_t stdin_pipe2;
static uv_pipe_t stdout_pipe2;
static void on_pipe_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) {
static void on_pipe_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) {
ASSERT(nread > 0);
ASSERT(memcmp("hello world\n", buf->base, nread) == 0);
on_pipe_read_called++;
free(buf->base);
uv_close((uv_handle_t*)&stdin_pipe, close_cb);
uv_close((uv_handle_t*)&stdout_pipe, close_cb);
uv_read_stop(pipe);
}
@ -204,52 +218,81 @@ int stdio_over_pipes_helper(void) {
uv_write_t write_req[ARRAY_SIZE(buffers)];
uv_buf_t buf[ARRAY_SIZE(buffers)];
unsigned int i;
int j;
int r;
uv_loop_t* loop = uv_default_loop();
ASSERT(UV_NAMED_PIPE == uv_guess_handle(0));
ASSERT(UV_NAMED_PIPE == uv_guess_handle(1));
r = uv_pipe_init(loop, &stdin_pipe, 0);
r = uv_pipe_init(loop, &stdin_pipe1, 0);
ASSERT(r == 0);
r = uv_pipe_init(loop, &stdout_pipe, 0);
r = uv_pipe_init(loop, &stdout_pipe1, 0);
ASSERT(r == 0);
r = uv_pipe_init(loop, &stdin_pipe2, 0);
ASSERT(r == 0);
r = uv_pipe_init(loop, &stdout_pipe2, 0);
ASSERT(r == 0);
uv_pipe_open(&stdin_pipe, 0);
uv_pipe_open(&stdout_pipe, 1);
uv_pipe_open(&stdin_pipe1, 0);
uv_pipe_open(&stdout_pipe1, 1);
uv_pipe_open(&stdin_pipe2, 0);
uv_pipe_open(&stdout_pipe2, 1);
/* Unref both stdio handles to make sure that all writes complete. */
uv_unref((uv_handle_t*)&stdin_pipe);
uv_unref((uv_handle_t*)&stdout_pipe);
for (j = 0; j < 2; j++) {
/* Unref both stdio handles to make sure that all writes complete. */
uv_unref((uv_handle_t*) &stdin_pipe1);
uv_unref((uv_handle_t*) &stdout_pipe1);
uv_unref((uv_handle_t*) &stdin_pipe2);
uv_unref((uv_handle_t*) &stdout_pipe2);
for (i = 0; i < ARRAY_SIZE(buffers); i++) {
buf[i] = uv_buf_init((char*)buffers[i], strlen(buffers[i]));
}
for (i = 0; i < ARRAY_SIZE(buffers); i++) {
buf[i] = uv_buf_init((char*) buffers[i], strlen(buffers[i]));
}
for (i = 0; i < ARRAY_SIZE(buffers); i++) {
r = uv_write(&write_req[i], (uv_stream_t*)&stdout_pipe, &buf[i], 1,
after_pipe_write);
for (i = 0; i < ARRAY_SIZE(buffers); i++) {
r = uv_write(&write_req[i],
(uv_stream_t*) (j == 0 ? &stdout_pipe1 : &stdout_pipe2),
&buf[i],
1,
after_pipe_write);
ASSERT(r == 0);
}
notify_parent_process();
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(after_write_called == 7 * (j + 1));
ASSERT(on_pipe_read_called == j);
ASSERT(close_cb_called == 0);
uv_ref((uv_handle_t*) &stdout_pipe1);
uv_ref((uv_handle_t*) &stdin_pipe1);
uv_ref((uv_handle_t*) &stdout_pipe2);
uv_ref((uv_handle_t*) &stdin_pipe2);
r = uv_read_start((uv_stream_t*) (j == 0 ? &stdin_pipe1 : &stdin_pipe2),
on_read_alloc,
on_pipe_read);
ASSERT(r == 0);
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(after_write_called == 7 * (j + 1));
ASSERT(on_pipe_read_called == j + 1);
ASSERT(close_cb_called == 0);
}
notify_parent_process();
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(after_write_called == 7);
ASSERT(on_pipe_read_called == 0);
ASSERT(close_cb_called == 0);
uv_ref((uv_handle_t*)&stdout_pipe);
uv_ref((uv_handle_t*)&stdin_pipe);
r = uv_read_start((uv_stream_t*)&stdin_pipe, on_read_alloc, on_pipe_read);
ASSERT(r == 0);
uv_close((uv_handle_t*)&stdin_pipe1, close_cb);
uv_close((uv_handle_t*)&stdout_pipe1, close_cb);
uv_close((uv_handle_t*)&stdin_pipe2, close_cb);
uv_close((uv_handle_t*)&stdout_pipe2, close_cb);
uv_run(loop, UV_RUN_DEFAULT);
ASSERT(after_write_called == 7);
ASSERT(on_pipe_read_called == 1);
ASSERT(close_cb_called == 2);
ASSERT(after_write_called == 14);
ASSERT(on_pipe_read_called == 2);
ASSERT(close_cb_called == 4);
MAKE_VALGRIND_HAPPY();
return 0;