Skip to content

Commit a6d06ba

Browse files
yury-ssaghul
authored andcommitted
win: fix crash when closing a pipe after a failed bind
uv_pipe_pending_instances() sets the UV_HANDLE_PIPESERVER flag before the pipe is bound. When the subsequent bind fails, e.g. with UV_EADDRINUSE after losing a bind race on a well-known pipe name, uv_pipe_bind2() frees accept_reqs and resets it to NULL, but the flag stays set. Closing the handle then dereferences the NULL accept_reqs array in uv__pipe_close() (release builds crash with an access violation; debug builds trip the assert in uv__pipe_endgame()). Tolerate accept_reqs == NULL at both cleanup sites.
1 parent e774099 commit a6d06ba

3 files changed

Lines changed: 41 additions & 6 deletions

File tree

src/win/pipe.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,8 @@ void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
730730
}
731731

732732
if (handle->flags & UV_HANDLE_PIPESERVER) {
733-
assert(handle->pipe.serv.accept_reqs);
733+
/* accept_reqs is NULL when uv_pipe_pending_instances() was called but
734+
* the pipe was never successfully bound. */
734735
uv__free(handle->pipe.serv.accept_reqs);
735736
handle->pipe.serv.accept_reqs = NULL;
736737
}
@@ -1248,11 +1249,15 @@ void uv__pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
12481249
}
12491250

12501251
if (handle->flags & UV_HANDLE_PIPESERVER) {
1251-
for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
1252-
pipeHandle = handle->pipe.serv.accept_reqs[i].pipeHandle;
1253-
if (pipeHandle != INVALID_HANDLE_VALUE) {
1254-
CloseHandle(pipeHandle);
1255-
handle->pipe.serv.accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE;
1252+
/* accept_reqs is NULL when uv_pipe_pending_instances() was called but
1253+
* the pipe was never successfully bound. */
1254+
if (handle->pipe.serv.accept_reqs != NULL) {
1255+
for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
1256+
pipeHandle = handle->pipe.serv.accept_reqs[i].pipeHandle;
1257+
if (pipeHandle != INVALID_HANDLE_VALUE) {
1258+
CloseHandle(pipeHandle);
1259+
handle->pipe.serv.accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE;
1260+
}
12561261
}
12571262
}
12581263
handle->handle = INVALID_HANDLE_VALUE;

test/test-list.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ TEST_DECLARE (udp_send_fail_nbufs)
220220
TEST_DECLARE (udp_sendmmsg_error)
221221
TEST_DECLARE (udp_try_send)
222222
TEST_DECLARE (pipe_bind_error_addrinuse)
223+
TEST_DECLARE (pipe_bind_error_addrinuse_pending_instances)
223224
TEST_DECLARE (pipe_bind_error_addrnotavail)
224225
TEST_DECLARE (pipe_bind_error_inval)
225226
TEST_DECLARE (pipe_connect_close_multiple)
@@ -881,6 +882,7 @@ TASK_LIST_START
881882
#endif
882883

883884
TEST_ENTRY (pipe_bind_error_addrinuse)
885+
TEST_ENTRY (pipe_bind_error_addrinuse_pending_instances)
884886
TEST_ENTRY (pipe_bind_error_addrnotavail)
885887
TEST_ENTRY (pipe_bind_error_inval)
886888
TEST_ENTRY (pipe_connect_close_multiple)

test/test-pipe-bind-error.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,34 @@ TEST_IMPL(pipe_bind_error_addrinuse) {
7373
}
7474

7575

76+
TEST_IMPL(pipe_bind_error_addrinuse_pending_instances) {
77+
uv_pipe_t server1, server2;
78+
int r;
79+
80+
r = uv_pipe_init(uv_default_loop(), &server1, 0);
81+
ASSERT_OK(r);
82+
uv_pipe_pending_instances(&server1, 32);
83+
r = uv_pipe_bind(&server1, TEST_PIPENAME);
84+
ASSERT_OK(r);
85+
86+
r = uv_pipe_init(uv_default_loop(), &server2, 0);
87+
ASSERT_OK(r);
88+
uv_pipe_pending_instances(&server2, 32);
89+
r = uv_pipe_bind(&server2, TEST_PIPENAME);
90+
ASSERT_EQ(r, UV_EADDRINUSE);
91+
92+
uv_close((uv_handle_t*)&server1, close_cb);
93+
uv_close((uv_handle_t*)&server2, close_cb);
94+
95+
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
96+
97+
ASSERT_EQ(2, close_cb_called);
98+
99+
MAKE_VALGRIND_HAPPY(uv_default_loop());
100+
return 0;
101+
}
102+
103+
76104
TEST_IMPL(pipe_bind_error_addrnotavail) {
77105
uv_pipe_t server;
78106
int r;

0 commit comments

Comments
 (0)