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:
parent
4e53af9120
commit
2256be01b0
@ -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;
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user