From 59d33502cbf00d4f406e8120598374fd1bc72df6 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Fri, 25 Oct 2013 12:56:37 +0400 Subject: [PATCH 1/6] unix: fix reopened fd bug When fd is closed and new one (with the same number) is opened inside kqueue/epoll/port loop's callback - stale events might invoke callbacks on wrong watchers. Check if watcher was changed after invocation and invalidate all events with the same fd. fix #826 --- src/unix/core.c | 20 ++++++++++++++++++-- src/unix/darwin.c | 21 +++++++++++++++++++++ src/unix/internal.h | 1 + src/unix/kqueue.c | 9 +++++++++ src/unix/linux-core.c | 30 ++++++++++++++++++++++++++++++ src/unix/sunos.c | 30 ++++++++++++++++++++++++++++++ 6 files changed, 109 insertions(+), 2 deletions(-) diff --git a/src/unix/core.c b/src/unix/core.c index e8e5f9e62f..991b18fa2e 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -595,20 +595,33 @@ static unsigned int next_power_of_two(unsigned int val) { static void maybe_resize(uv_loop_t* loop, unsigned int len) { uv__io_t** watchers; + void* fake_watcher_list; + void* fake_watcher_count; unsigned int nwatchers; unsigned int i; if (len <= loop->nwatchers) return; - nwatchers = next_power_of_two(len); - watchers = realloc(loop->watchers, nwatchers * sizeof(loop->watchers[0])); + nwatchers = next_power_of_two(len + 2) - 2; + watchers = realloc(loop->watchers, + (nwatchers + 2) * sizeof(loop->watchers[0])); if (watchers == NULL) abort(); + /* Copy watchers, preserving fake one in the end */ + if (loop->watchers == NULL) { + fake_watcher_list = watchers[loop->nwatchers]; + fake_watcher_count = watchers[loop->nwatchers + 1]; + } else { + fake_watcher_list = NULL; + fake_watcher_count = NULL; + } for (i = loop->nwatchers; i < nwatchers; i++) watchers[i] = NULL; + watchers[nwatchers] = fake_watcher_list; + watchers[nwatchers + 1] = fake_watcher_count; loop->watchers = watchers; loop->nwatchers = nwatchers; @@ -700,6 +713,9 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_close(uv_loop_t* loop, uv__io_t* w) { uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT); ngx_queue_remove(&w->pending_queue); + + /* Remove stale events for this file descriptor */ + uv__platform_invalidate_fd(loop, w->fd); } diff --git a/src/unix/darwin.c b/src/unix/darwin.c index 77e662f4e1..86624eae79 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -102,6 +102,27 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct kevent* events; + intptr_t i; + intptr_t nfds; + + /* No watchers - no fake watcher */ + if (loop->watchers == NULL) + return; + + events = (struct kevent*) loop->watchers[loop->nwatchers]; + nfds = (intptr_t) loop->watchers[loop->nwatchers + 1]; + if (events == NULL) + return; + + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].ident == fd) + events[i].ident = -1; +} + + static void uv__cf_loop_runner(void* arg) { uv_loop_t* loop; diff --git a/src/unix/internal.h b/src/unix/internal.h index 61cb1ec1f0..35aa894a54 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -183,6 +183,7 @@ uint64_t uv__hrtime(void); int uv__kqueue_init(uv_loop_t* loop); int uv__platform_loop_init(uv_loop_t* loop, int default_loop); void uv__platform_loop_delete(uv_loop_t* loop); +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd); /* various */ void uv__async_close(uv_async_t* handle); diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index d99d6e1b83..596022679b 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -162,11 +162,18 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { nevents = 0; + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) ((intptr_t) nfds); for (i = 0; i < nfds; i++) { ev = events + i; fd = ev->ident; w = loop->watchers[fd]; + /* Skip invalidated events */ + if (fd == -1) + continue; + if (w == NULL) { /* File descriptor that we've stopped watching, disarm it. */ /* TODO batch up */ @@ -227,6 +234,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w->cb(loop, w, revents); nevents++; } + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index cb6df78983..ffa2b04073 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -97,6 +97,27 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct uv__epoll_event* events; + intptr_t i; + intptr_t nfds; + + /* No watchers - no fake watcher */ + if (loop->watchers == NULL) + return; + + events = (struct kevent*) loop->watchers[loop->nwatchers]; + nfds = (intptr_t) loop->watchers[loop->nwatchers + 1]; + if (events == NULL) + return; + + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].data == fd) + events[i].data = -1; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { struct uv__epoll_event events[1024]; struct uv__epoll_event* pe; @@ -190,10 +211,17 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { nevents = 0; + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) ((intptr_t) nfds); for (i = 0; i < nfds; i++) { pe = events + i; fd = pe->data; + /* Skip invalidated events */ + if (fd == -1) + continue; + assert(fd >= 0); assert((unsigned) fd < loop->nwatchers); @@ -220,6 +248,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { w->cb(loop, w, masked_events); nevents++; } + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 3fbb50c9be..a03d333573 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -87,6 +87,27 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } +void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { + struct port_event* events; + intptr_t i; + intptr_t nfds; + + /* No watchers - no fake watcher */ + if (loop->watchers == NULL) + return; + + events = (struct port_event*) loop->watchers[loop->nwatchers]; + nfds = (intptr_t) loop->watchers[loop->nwatchers + 1]; + if (events == NULL) + return; + + /* Invalidate events with same file descriptor */ + for (i = 0; i < nfds; i++) + if ((int) events[i].portev_object == fd) + events[i].portev_object = -1; +} + + void uv__io_poll(uv_loop_t* loop, int timeout) { struct port_event events[1024]; struct port_event* pe; @@ -173,10 +194,17 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { nevents = 0; + assert(loop->watchers != NULL); + loop->watchers[loop->nwatchers] = (void*) events; + loop->watchers[loop->nwatchers + 1] = (void*) ((intptr_t) nfds); for (i = 0; i < nfds; i++) { pe = events + i; fd = pe->portev_object; + /* Skip invalidated events */ + if (fd == -1) + continue; + assert(fd >= 0); assert((unsigned) fd < loop->nwatchers); @@ -193,6 +221,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (w->pevents != 0 && ngx_queue_empty(&w->watcher_queue)) ngx_queue_insert_tail(&loop->watcher_queue, &w->watcher_queue); } + loop->watchers[loop->nwatchers] = NULL; + loop->watchers[loop->nwatchers + 1] = NULL; if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { From 00ace9016b9e1cc4ede8c1c4ea15068485e34b72 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Sat, 2 Nov 2013 22:37:09 +0400 Subject: [PATCH 2/6] test --- build.mk | 1 + checksparse.sh | 1 + test/test-list.h | 2 + test/test-tcp-close-accept.c | 154 +++++++++++++++++++++++++++++++++++ uv.gyp | 1 + 5 files changed, 159 insertions(+) create mode 100644 test/test-tcp-close-accept.c diff --git a/build.mk b/build.mk index 2b86ba0ecb..2f2dabe814 100644 --- a/build.mk +++ b/build.mk @@ -114,6 +114,7 @@ TESTS= \ test/test-tcp-bind6-error.o \ test/test-tcp-bind-error.o \ test/test-tcp-close.o \ + test/test-tcp-close-accept.o \ test/test-tcp-close-while-connecting.o \ test/test-tcp-connect6-error.o \ test/test-tcp-connect-error-after-write.o \ diff --git a/checksparse.sh b/checksparse.sh index 4a508e2668..43c9441e23 100755 --- a/checksparse.sh +++ b/checksparse.sh @@ -133,6 +133,7 @@ test/test-stdio-over-pipes.c test/test-tcp-bind-error.c test/test-tcp-bind6-error.c test/test-tcp-close-while-connecting.c +test/test-tcp-close-accept.c test/test-tcp-close.c test/test-tcp-connect-error-after-write.c test/test-tcp-connect-error.c diff --git a/test/test-list.h b/test/test-list.h index d883496f2e..f1e950e5b4 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -64,6 +64,7 @@ TEST_DECLARE (tcp_connect_error_fault) TEST_DECLARE (tcp_connect_timeout) TEST_DECLARE (tcp_close_while_connecting) TEST_DECLARE (tcp_close) +TEST_DECLARE (tcp_close_accept) TEST_DECLARE (tcp_flags) TEST_DECLARE (tcp_write_to_half_open_connection) TEST_DECLARE (tcp_unexpected_read) @@ -298,6 +299,7 @@ TASK_LIST_START TEST_ENTRY (tcp_connect_timeout) TEST_ENTRY (tcp_close_while_connecting) TEST_ENTRY (tcp_close) + TEST_ENTRY (tcp_close_accept) TEST_ENTRY (tcp_flags) TEST_ENTRY (tcp_write_to_half_open_connection) TEST_ENTRY (tcp_unexpected_read) diff --git a/test/test-tcp-close-accept.c b/test/test-tcp-close-accept.c new file mode 100644 index 0000000000..f02849608d --- /dev/null +++ b/test/test-tcp-close-accept.c @@ -0,0 +1,154 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#include +#include + +static struct sockaddr_in addr; +static uv_tcp_t tcp_server; +static uv_tcp_t tcp_outgoing[2]; +static uv_tcp_t tcp_incoming[ARRAY_SIZE(tcp_outgoing)]; +static uv_connect_t connect_reqs[ARRAY_SIZE(tcp_outgoing)]; +static uv_tcp_t tcp_check; +static uv_connect_t tcp_check_req; +static uv_write_t write_reqs[ARRAY_SIZE(tcp_outgoing)]; +static char buf[1]; +static unsigned int got_connections; +static unsigned int close_cb_called; +static unsigned int write_cb_called; +static unsigned int read_cb_called; + +static void close_cb(uv_handle_t* handle) { + close_cb_called++; +} + +static void write_cb(uv_write_t* req, int status) { + write_cb_called++; +} + +static void connect_cb(uv_connect_t* req, int status) { + unsigned int i; + uv_buf_t buf; + uv_stream_t* outgoing; + + if (req == &tcp_check_req) { + /* Close check and server, time to finish test */ + uv_close((uv_handle_t*) &tcp_incoming[0], close_cb); + uv_close((uv_handle_t*) &tcp_check, close_cb); + uv_close((uv_handle_t*) &tcp_server, close_cb); + return; + } + + i = (unsigned int) ((intptr_t) req - (intptr_t) connect_reqs) / sizeof(*req); + ASSERT(i < ARRAY_SIZE(connect_reqs)); + + buf = uv_buf_init("x", 1); + outgoing = (uv_stream_t*) &tcp_outgoing[i]; + ASSERT(0 == uv_write(&write_reqs[i], outgoing, &buf, 1, write_cb)); +} + +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) { + return uv_buf_init(buf, sizeof(buf)); +} + +static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t b) { + uv_loop_t* loop; + unsigned int i; + + /* Only first stream should receive read events */ + ASSERT(stream == (uv_stream_t*) &tcp_incoming[0]); + ASSERT(0 == uv_read_stop(stream)); + ASSERT(1 == nread); + + loop = stream->loop; + read_cb_called++; + + /* Close all active incomings, except current one */ + for (i = 1; i < got_connections; i++) + uv_close((uv_handle_t*) &tcp_incoming[i], close_cb); + + /* Create new fd that should be one of the closed incomings */ + ASSERT(0 == uv_tcp_init(loop, &tcp_check)); + ASSERT(0 == uv_tcp_connect(&tcp_check_req, &tcp_check, addr, connect_cb)); + + /* Start reading to add watcher to the loop */ + ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_check, alloc_cb, read_cb)); +} + +static void connection_cb(uv_stream_t* server, int status) { + unsigned int i; + uv_tcp_t* incoming; + + ASSERT(server == (uv_stream_t*) &tcp_server); + + /* Ignore tcp_check connection */ + if (got_connections == ARRAY_SIZE(tcp_incoming)) + return; + + /* Accept everyone */ + incoming = &tcp_incoming[got_connections++]; + ASSERT(0 == uv_tcp_init(server->loop, incoming)); + ASSERT(0 == uv_accept(server, (uv_stream_t*) incoming)); + + if (got_connections != ARRAY_SIZE(tcp_incoming)) + return; + + /* Once all clients are accepted - start reading */ + for (i = 0; i < ARRAY_SIZE(tcp_incoming); i++) { + incoming = &tcp_incoming[i]; + ASSERT(0 == uv_read_start((uv_stream_t*) incoming, alloc_cb, read_cb)); + } +} + +TEST_IMPL(tcp_close_accept) { + unsigned int i; + uv_loop_t* loop; + uv_tcp_t* client; + + loop = uv_default_loop(); + addr = uv_ip4_addr("0.0.0.0", TEST_PORT); + + ASSERT(0 == uv_tcp_init(loop, &tcp_server)); + ASSERT(0 == uv_tcp_bind(&tcp_server, addr)); + ASSERT(0 == uv_listen((uv_stream_t*) &tcp_server, + ARRAY_SIZE(tcp_outgoing), + connection_cb)); + + for (i = 0; i < ARRAY_SIZE(tcp_outgoing); i++) { + client = tcp_outgoing + i; + + ASSERT(0 == uv_tcp_init(loop, client)); + ASSERT(0 == uv_tcp_connect(&connect_reqs[i], client, addr, connect_cb)); + } + + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(ARRAY_SIZE(tcp_outgoing) == got_connections); + ASSERT((ARRAY_SIZE(tcp_outgoing) + 2) == close_cb_called); + ASSERT(ARRAY_SIZE(tcp_outgoing) == write_cb_called); + ASSERT(1 == read_cb_called); + + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/uv.gyp b/uv.gyp index 7d43d87ea5..96a57609f7 100644 --- a/uv.gyp +++ b/uv.gyp @@ -335,6 +335,7 @@ 'test/test-tcp-bind-error.c', 'test/test-tcp-bind6-error.c', 'test/test-tcp-close.c', + 'test/test-tcp-close-accept.c', 'test/test-tcp-close-while-connecting.c', 'test/test-tcp-connect-error-after-write.c', 'test/test-tcp-shutdown-after-write.c', From ee3810c6f5b51a0f8d932d28a373ce1a8beae6d1 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Sat, 2 Nov 2013 22:41:09 +0400 Subject: [PATCH 3/6] fix test --- test/test-tcp-close-accept.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/test-tcp-close-accept.c b/test/test-tcp-close-accept.c index f02849608d..385479d4ee 100644 --- a/test/test-tcp-close-accept.c +++ b/test/test-tcp-close-accept.c @@ -53,10 +53,11 @@ static void connect_cb(uv_connect_t* req, int status) { uv_stream_t* outgoing; if (req == &tcp_check_req) { - /* Close check and server, time to finish test */ + ASSERT(status != 0); + + /* Close check and incoming[0], time to finish test */ uv_close((uv_handle_t*) &tcp_incoming[0], close_cb); uv_close((uv_handle_t*) &tcp_check, close_cb); - uv_close((uv_handle_t*) &tcp_server, close_cb); return; } @@ -91,9 +92,10 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t b) { /* Create new fd that should be one of the closed incomings */ ASSERT(0 == uv_tcp_init(loop, &tcp_check)); ASSERT(0 == uv_tcp_connect(&tcp_check_req, &tcp_check, addr, connect_cb)); - - /* Start reading to add watcher to the loop */ ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_check, alloc_cb, read_cb)); + + /* Close server, so noone will connect to it */ + uv_close((uv_handle_t*) &tcp_server, close_cb); } static void connection_cb(uv_stream_t* server, int status) { From bb3d2806fa5ae44e33518282dc3d022370fd8dfe Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Sat, 2 Nov 2013 22:54:01 +0400 Subject: [PATCH 4/6] description of test --- test/test-tcp-close-accept.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/test-tcp-close-accept.c b/test/test-tcp-close-accept.c index 385479d4ee..29caacfe50 100644 --- a/test/test-tcp-close-accept.c +++ b/test/test-tcp-close-accept.c @@ -44,6 +44,7 @@ static void close_cb(uv_handle_t* handle) { } static void write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); write_cb_called++; } @@ -61,6 +62,7 @@ static void connect_cb(uv_connect_t* req, int status) { return; } + ASSERT(status == 0); i = (unsigned int) ((intptr_t) req - (intptr_t) connect_reqs) / sizeof(*req); ASSERT(i < ARRAY_SIZE(connect_reqs)); @@ -128,6 +130,23 @@ TEST_IMPL(tcp_close_accept) { uv_loop_t* loop; uv_tcp_t* client; + /* + * A little explanation of what'll go below: + * + * We'll create server and connect to it using two clients, each writing one + * byte once connected. + * + * When all clients will be accepted by server - we'll start reading from them + * and, on first client's first byte, will close second client and server. + * After that, we'll immediately initiate new connection to server using + * tcp_check handle (thus, reusing fd from second client). + * + * In this situation uv__io_poll()'s event list should still contain read + * event for second client, and, if not cleaned up properly, `tcp_check` will + * receive stale event of second incoming and invoke `connect_cb` with zero + * status. + */ + loop = uv_default_loop(); addr = uv_ip4_addr("0.0.0.0", TEST_PORT); From 89e241d73b7b7b04407eba49b816826b218354f2 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Sun, 3 Nov 2013 14:56:06 +0400 Subject: [PATCH 5/6] fixes --- src/unix/darwin.c | 6 +++--- src/unix/kqueue.c | 2 +- src/unix/linux-core.c | 8 ++++---- src/unix/sunos.c | 6 +++--- test/test-tcp-close-accept.c | 12 +++++++----- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/unix/darwin.c b/src/unix/darwin.c index 86624eae79..4d100f0da9 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -104,15 +104,15 @@ void uv__platform_loop_delete(uv_loop_t* loop) { void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { struct kevent* events; - intptr_t i; - intptr_t nfds; + uintptr_t i; + uintptr_t nfds; /* No watchers - no fake watcher */ if (loop->watchers == NULL) return; events = (struct kevent*) loop->watchers[loop->nwatchers]; - nfds = (intptr_t) loop->watchers[loop->nwatchers + 1]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; if (events == NULL) return; diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 596022679b..9874bf9487 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -164,7 +164,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { assert(loop->watchers != NULL); loop->watchers[loop->nwatchers] = (void*) events; - loop->watchers[loop->nwatchers + 1] = (void*) ((intptr_t) nfds); + loop->watchers[loop->nwatchers + 1] = (void*) ((uintptr_t) nfds); for (i = 0; i < nfds; i++) { ev = events + i; fd = ev->ident; diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index ffa2b04073..643d3cfb10 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -99,15 +99,15 @@ void uv__platform_loop_delete(uv_loop_t* loop) { void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { struct uv__epoll_event* events; - intptr_t i; - intptr_t nfds; + uintptr_t i; + uintptr_t nfds; /* No watchers - no fake watcher */ if (loop->watchers == NULL) return; - events = (struct kevent*) loop->watchers[loop->nwatchers]; - nfds = (intptr_t) loop->watchers[loop->nwatchers + 1]; + events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; if (events == NULL) return; diff --git a/src/unix/sunos.c b/src/unix/sunos.c index a03d333573..ff8fced5ca 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -89,15 +89,15 @@ void uv__platform_loop_delete(uv_loop_t* loop) { void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { struct port_event* events; - intptr_t i; - intptr_t nfds; + uintptr_t i; + uintptr_t nfds; /* No watchers - no fake watcher */ if (loop->watchers == NULL) return; events = (struct port_event*) loop->watchers[loop->nwatchers]; - nfds = (intptr_t) loop->watchers[loop->nwatchers + 1]; + nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; if (events == NULL) return; diff --git a/test/test-tcp-close-accept.c b/test/test-tcp-close-accept.c index 29caacfe50..06ddbdfaca 100644 --- a/test/test-tcp-close-accept.c +++ b/test/test-tcp-close-accept.c @@ -33,7 +33,6 @@ static uv_connect_t connect_reqs[ARRAY_SIZE(tcp_outgoing)]; static uv_tcp_t tcp_check; static uv_connect_t tcp_check_req; static uv_write_t write_reqs[ARRAY_SIZE(tcp_outgoing)]; -static char buf[1]; static unsigned int got_connections; static unsigned int close_cb_called; static unsigned int write_cb_called; @@ -63,8 +62,9 @@ static void connect_cb(uv_connect_t* req, int status) { } ASSERT(status == 0); - i = (unsigned int) ((intptr_t) req - (intptr_t) connect_reqs) / sizeof(*req); - ASSERT(i < ARRAY_SIZE(connect_reqs)); + ASSERT(connect_reqs <= req && + req <= (connect_reqs + ARRAY_SIZE(connect_reqs))); + i = (unsigned int) (req - connect_reqs) / sizeof(*req); buf = uv_buf_init("x", 1); outgoing = (uv_stream_t*) &tcp_outgoing[i]; @@ -72,6 +72,8 @@ static void connect_cb(uv_connect_t* req, int status) { } static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) { + static char buf[1]; + return uv_buf_init(buf, sizeof(buf)); } @@ -96,7 +98,7 @@ static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t b) { ASSERT(0 == uv_tcp_connect(&tcp_check_req, &tcp_check, addr, connect_cb)); ASSERT(0 == uv_read_start((uv_stream_t*) &tcp_check, alloc_cb, read_cb)); - /* Close server, so noone will connect to it */ + /* Close server, so no one will connect to it */ uv_close((uv_handle_t*) &tcp_server, close_cb); } @@ -131,7 +133,7 @@ TEST_IMPL(tcp_close_accept) { uv_tcp_t* client; /* - * A little explanation of what'll go below: + * A little explanation of what goes on below: * * We'll create server and connect to it using two clients, each writing one * byte once connected. From 6b9a7bb1f176a04eb375b903691e37eaf5b097a6 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Sun, 3 Nov 2013 21:22:47 +0400 Subject: [PATCH 6/6] fixes --- src/unix/darwin.c | 4 +--- src/unix/linux-core.c | 4 +--- src/unix/sunos.c | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/unix/darwin.c b/src/unix/darwin.c index 4d100f0da9..0310254332 100644 --- a/src/unix/darwin.c +++ b/src/unix/darwin.c @@ -107,9 +107,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { uintptr_t i; uintptr_t nfds; - /* No watchers - no fake watcher */ - if (loop->watchers == NULL) - return; + assert(loop->watchers != NULL); events = (struct kevent*) loop->watchers[loop->nwatchers]; nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; diff --git a/src/unix/linux-core.c b/src/unix/linux-core.c index 643d3cfb10..efe5e181eb 100644 --- a/src/unix/linux-core.c +++ b/src/unix/linux-core.c @@ -102,9 +102,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { uintptr_t i; uintptr_t nfds; - /* No watchers - no fake watcher */ - if (loop->watchers == NULL) - return; + assert(loop->watchers != NULL); events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers]; nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1]; diff --git a/src/unix/sunos.c b/src/unix/sunos.c index ff8fced5ca..93bcb8286f 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -92,9 +92,7 @@ void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) { uintptr_t i; uintptr_t nfds; - /* No watchers - no fake watcher */ - if (loop->watchers == NULL) - return; + assert(loop->watchers != NULL); events = (struct port_event*) loop->watchers[loop->nwatchers]; nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];