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:
parent
a5da270f78
commit
56fc3de48c
@ -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;
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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*)∈
|
||||
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*) ∈
|
||||
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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user