unix: catch some cases of watching fd twice

Libuv does not support multiple handles watching the same file
descriptor.  That condition is caught by an assert but it's detached
from the call site and therefore not always trivial to track down.

This commit turns cases where we can easily detect duplicates into
runtime `UV_EEXIST` errors.  More work is needed to catch _all_ cases.

Partially addresses https://github.com/libuv/libuv/issues/1172.

PR-URL: https://github.com/libuv/libuv/pull/1851
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
This commit is contained in:
Ben Noordhuis 2018-05-28 16:45:17 +02:00
parent 4e53af9120
commit 2256be01b0
8 changed files with 46 additions and 0 deletions

View File

@ -927,6 +927,11 @@ int uv__io_active(const uv__io_t* w, unsigned int events) {
}
int uv__fd_exists(uv_loop_t* loop, int fd) {
return (unsigned) fd < loop->nwatchers && loop->watchers[fd] != NULL;
}
int uv_getrusage(uv_rusage_t* rusage) {
struct rusage usage;

View File

@ -219,6 +219,7 @@ int uv__io_active(const uv__io_t* w, unsigned int events);
int uv__io_check_fd(uv_loop_t* loop, int fd);
void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
int uv__io_fork(uv_loop_t* loop);
int uv__fd_exists(uv_loop_t* loop, int fd);
/* async */
void uv__async_stop(uv_loop_t* loop);

View File

@ -134,6 +134,9 @@ void uv__pipe_close(uv_pipe_t* handle) {
int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
int err;
if (uv__fd_exists(handle->loop, fd))
return UV_EEXIST;
err = uv__nonblock(fd, 1);
if (err)
return err;

View File

@ -68,6 +68,9 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
int err;
if (uv__fd_exists(loop, fd))
return UV_EEXIST;
err = uv__io_check_fd(loop, fd);
if (err)
return err;

View File

@ -263,6 +263,9 @@ int uv__tcp_connect(uv_connect_t* req,
int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
int err;
if (uv__fd_exists(handle->loop, sock))
return UV_EEXIST;
err = uv__nonblock(sock, 1);
if (err)
return err;

View File

@ -624,6 +624,9 @@ int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
if (handle->io_watcher.fd != -1)
return UV_EBUSY;
if (uv__fd_exists(handle->loop, sock))
return UV_EEXIST;
err = uv__nonblock(sock, 1);
if (err)
return err;

View File

@ -181,6 +181,20 @@ TEST_IMPL(tcp_open) {
connect_cb);
ASSERT(r == 0);
#ifndef _WIN32
{
uv_tcp_t client2;
r = uv_tcp_init(uv_default_loop(), &client2);
ASSERT(r == 0);
r = uv_tcp_open(&client2, sock);
ASSERT(r == UV_EEXIST);
uv_close((uv_handle_t*) &client2, NULL);
}
#endif /* !_WIN32 */
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(shutdown_cb_called == 1);

View File

@ -164,6 +164,20 @@ TEST_IMPL(udp_open) {
send_cb);
ASSERT(r == 0);
#ifndef _WIN32
{
uv_udp_t client2;
r = uv_udp_init(uv_default_loop(), &client2);
ASSERT(r == 0);
r = uv_udp_open(&client2, sock);
ASSERT(r == UV_EEXIST);
uv_close((uv_handle_t*) &client2, NULL);
}
#endif /* !_WIN32 */
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
ASSERT(send_cb_called == 1);