diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index b2397e2df6de5f..8dc3955cad5bf3 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -225,3 +225,18 @@ Colin Snover Sakthipriyan Vairamani Eli Skeggs nmushell +Gireesh Punathil +Ryan Johnston +Adam Stylinski +Nathan Corvino +Wink Saville +Angel Leon +Louis DeJardin +Imran Iqbal +Petka Antonov +Ian Kronquist +kkdaemon +Yuval Brik +Joran Dirk Greef +Andrey Mazo +sztomi diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 42f10352b1cb35..af0743af72c8db 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,102 @@ +2015.12.15, Version 1.8.0 (Stable), 5467299450ecf61635657557b6e01aaaf6c3fdf4 + +Changes since version 1.7.5: + +* unix: fix memory leak in uv_interface_addresses (Jianghua Yang) + +* unix: make uv_guess_handle work properly for AIX (Gireesh Punathil) + +* fs: undo uv__req_init when uv__malloc failed (Jianghua Yang) + +* build: remove unused 'component' GYP option (Saúl Ibarra Corretgé) + +* include: remove duplicate extern declaration (Jianghua Yang) + +* win: use the MSVC provided snprintf where possible (Jason Williams) + +* win, test: fix compilation warning (Saúl Ibarra Corretgé) + +* win: fix compilation with VS < 2012 (Ryan Johnston) + +* stream: support empty uv_try_write on unix (Fedor Indutny) + +* unix: fix request handle leak in uv__udp_send (Jianghua Yang) + +* src: replace QUEUE_SPLIT with QUEUE_MOVE (Ben Noordhuis) + +* unix: use QUEUE_MOVE when iterating over lists (Ben Noordhuis) + +* unix: squelch harmless valgrind warning (Ben Noordhuis) + +* test: don't abort on setrlimit() failure (Ben Noordhuis) + +* unix: only undo fs req registration in async mode (Ben Noordhuis) + +* unix: fix uv__getiovmax return value (HungMingWu) + +* unix: make work with Solaris Studio. (Adam Stylinski) + +* test: fix fs_event_watch_file_currentdir flakiness (Santiago Gimeno) + +* unix: skip prohibited syscalls on tvOS and watchOS (Nathan Corvino) + +* test: use FQDN in getaddrinfo_fail test (Wink Saville) + +* docs: clarify documentation of uv_tcp_init_ex (Andrius Bentkus) + +* win: fix comment (Miodrag Milanovic) + +* doc: fix typo in README (Angel Leon) + +* darwin: abort() if (un)locking fs mutex fails (Ben Noordhuis) + +* pipe: enable inprocess uv_write2 on Windows (Louis DeJardin) + +* win: properly return UV_EBADF when _close() fails (Nicholas Vavilov) + +* test: skip process_title for AIX (Imran Iqbal) + +* misc: expose handle print APIs (Petka Antonov) + +* include: add stdio.h to uv.h (Saúl Ibarra Corretgé) + +* misc: remove unnecessary null pointer checks (Ian Kronquist) + +* test,freebsd: skip udp_dual_stack if not supported (Santiago Gimeno) + +* linux: don't retry dup2/dup3 on EINTR (Ben Noordhuis) + +* unix: don't retry dup2/dup3 on EINTR (Ben Noordhuis) + +* test: fix -Wtautological-pointer-compare warnings (Saúl Ibarra Corretgé) + +* win: map ERROR_BAD_PATHNAME to UV_ENOENT (Tony Kelman) + +* test: fix test/test-tty.c for AIX (Imran Iqbal) + +* android: support api level less than 21 (kkdaemon) + +* fsevents: fix race on simultaneous init+close (Fedor Indutny) + +* linux,fs: fix p{read,write}v with a 64bit offset (Saúl Ibarra Corretgé) + +* fs: add uv_fs_realpath() (Yuval Brik) + +* win: fix path for removed and renamed fs events (Joran Dirk Greef) + +* win: do not read more from stream than available (Jeremy Whitlock) + +* test: test that uv_close() doesn't corrupt QUEUE (Andrey Mazo) + +* unix: fix uv_fs_event_stop() from fs_event_cb (Andrey Mazo) + +* test: fix self-deadlocks in thread_rwlock_trylock (Ben Noordhuis) + +* src: remove non ascii character (sztomi) + +* test: fix test udp_multicast_join6 for AIX (Imran Iqbal) + + 2015.09.23, Version 1.7.5 (Stable), a8c1136de2cabf25b143021488cbaab05834daa8 Changes since version 1.7.4: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index fbf9527ae93a70..0ef781ff198804 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -200,6 +200,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-poll-closesocket.c \ test/test-poll.c \ test/test-process-title.c \ + test/test-queue-foreach-delete.c \ test/test-ref.c \ test/test-run-nowait.c \ test/test-run-once.c \ diff --git a/deps/uv/README.md b/deps/uv/README.md index 0ce26699716a1a..dfd24ba79d1850 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -119,7 +119,7 @@ Git tags are signed with the developer's key, they can be verified as follows: $ git verify-tag v1.6.1 Starting with libuv 1.7.0, the tarballs stored in the -[downloads site](http://dist.libuv.org/dist/) are signed and an accomanying +[downloads site](http://dist.libuv.org/dist/) are signed and an accompanying signature file sit alongside each. Once both the release tarball and the signature file are downloaded, the file can be verified as follows: diff --git a/deps/uv/appveyor.yml b/deps/uv/appveyor.yml index c9f55134e583dd..9aa63c5a5d2e73 100644 --- a/deps/uv/appveyor.yml +++ b/deps/uv/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.7.5.build{build} +version: v1.8.0.build{build} install: - cinst -y nsis diff --git a/deps/uv/common.gypi b/deps/uv/common.gypi index 392c85951e1ebd..7cebcde5f89137 100644 --- a/deps/uv/common.gypi +++ b/deps/uv/common.gypi @@ -4,7 +4,6 @@ 'target_arch%': 'ia32', # set v8's target architecture 'host_arch%': 'ia32', # set v8's host architecture 'uv_library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds - 'component%': 'static_library', # NB. these names match with what V8 expects 'msvs_multi_core_compile': '0', # we do enable multicore compiles, but not using the V8 way }, diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index c55a11847e255e..011bee2a891e73 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.7.5], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.8.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst index 33c04406f14d9e..69e283f4c67fc6 100644 --- a/deps/uv/docs/src/fs.rst +++ b/deps/uv/docs/src/fs.rst @@ -279,6 +279,16 @@ API Equivalent to :man:`readlink(2)`. +.. c:function:: int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) + + Equivalent to :man:`realpath(3)` on Unix. Windows uses ``GetFinalPathNameByHandle()``. + + .. note:: + This function is not implemented on Windows XP and Windows Server 2003. + On these systems, UV_ENOSYS is returned. + + .. versionadded:: 1.8.0 + .. c:function:: int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) .. c:function:: int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index e9ddba3db6a953..2ce0887db0c278 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -288,3 +288,41 @@ API .. note:: Not every platform can support nanosecond resolution; however, this value will always be in nanoseconds. + +.. c:function:: void uv_print_all_handles(uv_loop_t* loop, FILE* stream) + + Prints all handles associated with the given `loop` to the given `stream`. + + Example: + + :: + + uv_print_all_handles(uv_default_loop(), stderr); + /* + [--I] signal 0x1a25ea8 + [-AI] async 0x1a25cf0 + [R--] idle 0x1a7a8c8 + */ + + The format is `[flags] handle-type handle-address`. For `flags`: + + - `R` is printed for a handle that is referenced + - `A` is printed for a handle that is active + - `I` is printed for a handle that is internal + + .. warning:: + This function is meant for ad hoc debugging, there is no API/ABI + stability guarantees. + + .. versionadded:: 1.8.0 + +.. c:function:: void uv_print_active_handles(uv_loop_t* loop, FILE* stream) + + This is the same as :c:func:`uv_print_all_handles` except only active handles + are printed. + + .. warning:: + This function is meant for ad hoc debugging, there is no API/ABI + stability guarantees. + + .. versionadded:: 1.8.0 diff --git a/deps/uv/docs/src/tcp.rst b/deps/uv/docs/src/tcp.rst index dd18522d91d4eb..ca0c9b4ac5af4c 100644 --- a/deps/uv/docs/src/tcp.rst +++ b/deps/uv/docs/src/tcp.rst @@ -34,7 +34,7 @@ API .. c:function:: int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) - Initialize the handle with the specified flags. At the moment the lower 8 bits + Initialize the handle with the specified flags. At the moment only the lower 8 bits of the `flags` parameter are used as the socket domain. A socket will be created for the given domain. If the specified domain is ``AF_UNSPEC`` no socket is created, just like :c:func:`uv_tcp_init`. diff --git a/deps/uv/gyp_uv.py b/deps/uv/gyp_uv.py index 0491ff873f1af1..39933f624d5c40 100755 --- a/deps/uv/gyp_uv.py +++ b/deps/uv/gyp_uv.py @@ -83,9 +83,6 @@ def run_gyp(args): if not any(a.startswith('-Duv_library=') for a in args): args.append('-Duv_library=static_library') - if not any(a.startswith('-Dcomponent=') for a in args): - args.append('-Dcomponent=static_library') - # Some platforms (OpenBSD for example) don't have multiprocessing.synchronize # so gyp must be run with --no-parallel if not gyp_parallel_support: diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h index e1f26601a156c2..6e61f55ed20d85 100644 --- a/deps/uv/include/uv-version.h +++ b/deps/uv/include/uv-version.h @@ -31,8 +31,8 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 7 -#define UV_VERSION_PATCH 5 +#define UV_VERSION_MINOR 8 +#define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index f96026b603d34e..dd3111a960e69b 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -48,6 +48,7 @@ extern "C" { #include "uv-errno.h" #include "uv-version.h" #include +#include #if defined(_MSC_VER) && _MSC_VER < 1600 # include "stdint-msvc2008.h" @@ -424,6 +425,10 @@ UV_EXTERN int uv_is_active(const uv_handle_t* handle); UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg); +/* Helpers for ad hoc debugging, no API/ABI stability guaranteed. */ +UV_EXTERN void uv_print_all_handles(uv_loop_t* loop, FILE* stream); +UV_EXTERN void uv_print_active_handles(uv_loop_t* loop, FILE* stream); + UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb); UV_EXTERN int uv_send_buffer_size(uv_handle_t* handle, int* value); @@ -1083,7 +1088,8 @@ typedef enum { UV_FS_SYMLINK, UV_FS_READLINK, UV_FS_CHOWN, - UV_FS_FCHOWN + UV_FS_FCHOWN, + UV_FS_REALPATH } uv_fs_type; /* uv_fs_t is a subclass of uv_req_t. */ @@ -1235,6 +1241,10 @@ UV_EXTERN int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb); +UV_EXTERN int uv_fs_realpath(uv_loop_t* loop, + uv_fs_t* req, + const char* path, + uv_fs_cb cb); UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, @@ -1363,7 +1373,7 @@ UV_EXTERN int uv_chdir(const char* dir); UV_EXTERN uint64_t uv_get_free_memory(void); UV_EXTERN uint64_t uv_get_total_memory(void); -UV_EXTERN extern uint64_t uv_hrtime(void); +UV_EXTERN uint64_t uv_hrtime(void); UV_EXTERN void uv_disable_stdio_inheritance(void); diff --git a/deps/uv/src/inet.c b/deps/uv/src/inet.c index c948b2e7cfaf01..da63a688c4e424 100644 --- a/deps/uv/src/inet.c +++ b/deps/uv/src/inet.c @@ -55,11 +55,7 @@ static int inet_ntop4(const unsigned char *src, char *dst, size_t size) { char tmp[UV__INET_ADDRSTRLEN]; int l; -#ifndef _WIN32 l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); -#else - l = _snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); -#endif if (l <= 0 || (size_t) l >= size) { return UV_ENOSPC; } diff --git a/deps/uv/src/queue.h b/deps/uv/src/queue.h index 60c80000385be5..ff3540a0a51c84 100644 --- a/deps/uv/src/queue.h +++ b/deps/uv/src/queue.h @@ -30,6 +30,9 @@ typedef void *QUEUE[2]; #define QUEUE_DATA(ptr, type, field) \ ((type *) ((char *) (ptr) - offsetof(type, field))) +/* Important note: mutating the list while QUEUE_FOREACH is + * iterating over its elements results in undefined behavior. + */ #define QUEUE_FOREACH(q, h) \ for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q)) @@ -66,6 +69,17 @@ typedef void *QUEUE[2]; } \ while (0) +#define QUEUE_MOVE(h, n) \ + do { \ + if (QUEUE_EMPTY(h)) \ + QUEUE_INIT(n); \ + else { \ + QUEUE* q = QUEUE_HEAD(h); \ + QUEUE_SPLIT(h, q, n); \ + } \ + } \ + while (0) + #define QUEUE_INSERT_HEAD(h, q) \ do { \ QUEUE_NEXT(q) = QUEUE_NEXT(h); \ diff --git a/deps/uv/src/threadpool.c b/deps/uv/src/threadpool.c index 15d719944f1d0c..2c5152b4200875 100644 --- a/deps/uv/src/threadpool.c +++ b/deps/uv/src/threadpool.c @@ -223,13 +223,8 @@ void uv__work_done(uv_async_t* handle) { int err; loop = container_of(handle, uv_loop_t, wq_async); - QUEUE_INIT(&wq); - uv_mutex_lock(&loop->wq_mutex); - if (!QUEUE_EMPTY(&loop->wq)) { - q = QUEUE_HEAD(&loop->wq); - QUEUE_SPLIT(&loop->wq, q, &wq); - } + QUEUE_MOVE(&loop->wq, &wq); uv_mutex_unlock(&loop->wq_mutex); while (!QUEUE_EMPTY(&wq)) { diff --git a/deps/uv/src/unix/android-ifaddrs.c b/deps/uv/src/unix/android-ifaddrs.c index 71f7290b3263e0..30f681b7d04a41 100644 --- a/deps/uv/src/unix/android-ifaddrs.c +++ b/deps/uv/src/unix/android-ifaddrs.c @@ -1,6 +1,6 @@ /* Copyright (c) 2013, Kenneth MacKay -Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement n° 289016) +Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016) All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c index 9ff24aeb3d7d87..184b598126eb2c 100644 --- a/deps/uv/src/unix/async.c +++ b/deps/uv/src/unix/async.c @@ -78,12 +78,18 @@ void uv__async_close(uv_async_t* handle) { static void uv__async_event(uv_loop_t* loop, struct uv__async* w, unsigned int nevents) { + QUEUE queue; QUEUE* q; uv_async_t* h; - QUEUE_FOREACH(q, &loop->async_handles) { + QUEUE_MOVE(&loop->async_handles, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); h = QUEUE_DATA(q, uv_async_t, queue); + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&loop->async_handles, q); + if (cmpxchgi(&h->pending, 1, 0) == 0) continue; diff --git a/deps/uv/src/unix/atomic-ops.h b/deps/uv/src/unix/atomic-ops.h index 8fb157dcc61eb4..84e471838bede7 100644 --- a/deps/uv/src/unix/atomic-ops.h +++ b/deps/uv/src/unix/atomic-ops.h @@ -18,6 +18,11 @@ #include "internal.h" /* UV_UNUSED */ +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#include +#define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n) +#endif + UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)); UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)); UV_UNUSED(static void cpu_relax(void)); diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index e149357e076eb2..cedd86ed34a128 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -75,6 +75,10 @@ #include #endif +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 +# include /* for dlsym */ +#endif + static int uv__run_pending(uv_loop_t* loop); /* Verify that uv_buf_t is ABI-compatible with struct iovec. */ @@ -204,8 +208,14 @@ int uv__getiovmax(void) { return IOV_MAX; #elif defined(_SC_IOV_MAX) static int iovmax = -1; - if (iovmax == -1) + if (iovmax == -1) { iovmax = sysconf(_SC_IOV_MAX); + /* On some embedded devices (arm-linux-uclibc based ip camera), + * sysconf(_SC_IOV_MAX) can not get the correct value. The return + * value is -1 and the errno is EINPROGRESS. Degrade the value to 1. + */ + if (iovmax == -1) iovmax = 1; + } return iovmax; #else return 1024; @@ -721,9 +731,7 @@ static int uv__run_pending(uv_loop_t* loop) { if (QUEUE_EMPTY(&loop->pending_queue)) return 0; - QUEUE_INIT(&pq); - q = QUEUE_HEAD(&loop->pending_queue); - QUEUE_SPLIT(&loop->pending_queue, q, &pq); + QUEUE_MOVE(&loop->pending_queue, &pq); while (!QUEUE_EMPTY(&pq)) { q = QUEUE_HEAD(&pq); @@ -956,16 +964,12 @@ int uv__open_cloexec(const char* path, int flags) { int uv__dup2_cloexec(int oldfd, int newfd) { int r; #if defined(__FreeBSD__) && __FreeBSD__ >= 10 - do - r = dup3(oldfd, newfd, O_CLOEXEC); - while (r == -1 && errno == EINTR); + r = dup3(oldfd, newfd, O_CLOEXEC); if (r == -1) return -errno; return r; #elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC) - do - r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd); - while (r == -1 && errno == EINTR); + r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd); if (r != -1) return r; if (errno != EINVAL) @@ -976,7 +980,7 @@ int uv__dup2_cloexec(int oldfd, int newfd) { if (!no_dup3) { do r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC); - while (r == -1 && (errno == EINTR || errno == EBUSY)); + while (r == -1 && errno == EBUSY); if (r != -1) return r; if (errno != ENOSYS) @@ -990,9 +994,9 @@ int uv__dup2_cloexec(int oldfd, int newfd) { do r = dup2(oldfd, newfd); #if defined(__linux__) - while (r == -1 && (errno == EINTR || errno == EBUSY)); + while (r == -1 && errno == EBUSY); #else - while (r == -1 && errno == EINTR); + while (0); /* Never retry. */ #endif if (r == -1) @@ -1018,6 +1022,9 @@ int uv_os_homedir(char* buffer, size_t* size) { size_t len; long initsize; int r; +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**); +#endif if (buffer == NULL || size == NULL || *size == 0) return -EINVAL; @@ -1039,6 +1046,12 @@ int uv_os_homedir(char* buffer, size_t* size) { return 0; } +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 + getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r"); + if (getpwuid_r == NULL) + return -ENOSYS; +#endif + /* HOME is not set, so call getpwuid() */ initsize = sysconf(_SC_GETPW_R_SIZE_MAX); diff --git a/deps/uv/src/unix/darwin.c b/deps/uv/src/unix/darwin.c index dab6ca999d05f6..cf95da21693b9a 100644 --- a/deps/uv/src/unix/darwin.c +++ b/deps/uv/src/unix/darwin.c @@ -258,8 +258,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) + if (!(*addresses)) { + freeifaddrs(addrs); return -ENOMEM; + } address = *addresses; diff --git a/deps/uv/src/unix/dl.c b/deps/uv/src/unix/dl.c index 7c6d41c969b25f..fc1c052bb8122e 100644 --- a/deps/uv/src/unix/dl.c +++ b/deps/uv/src/unix/dl.c @@ -39,10 +39,8 @@ int uv_dlopen(const char* filename, uv_lib_t* lib) { void uv_dlclose(uv_lib_t* lib) { - if (lib->errmsg) { - uv__free(lib->errmsg); - lib->errmsg = NULL; - } + uv__free(lib->errmsg); + lib->errmsg = NULL; if (lib->handle) { /* Ignore errors. No good way to signal them without leaking memory. */ @@ -67,8 +65,7 @@ const char* uv_dlerror(const uv_lib_t* lib) { static int uv__dlerror(uv_lib_t* lib) { const char* errmsg; - if (lib->errmsg) - uv__free(lib->errmsg); + uv__free(lib->errmsg); errmsg = dlerror(); diff --git a/deps/uv/src/unix/freebsd.c b/deps/uv/src/unix/freebsd.c index c69608b139973b..b747abdf5bc46e 100644 --- a/deps/uv/src/unix/freebsd.c +++ b/deps/uv/src/unix/freebsd.c @@ -176,7 +176,7 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { int oid[4]; - if (process_title) uv__free(process_title); + uv__free(process_title); process_title = uv__strdup(title); oid[0] = CTL_KERN; @@ -373,8 +373,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) + if (!(*addresses)) { + freeifaddrs(addrs); return -ENOMEM; + } address = *addresses; diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index d739c282585f71..57b65be25a85ea 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -80,8 +80,10 @@ req->path = path; \ } else { \ req->path = uv__strdup(path); \ - if (req->path == NULL) \ + if (req->path == NULL) { \ + uv__req_unregister(loop, req); \ return -ENOMEM; \ + } \ } \ } \ while (0) @@ -97,8 +99,10 @@ path_len = strlen(path) + 1; \ new_path_len = strlen(new_path) + 1; \ req->path = uv__malloc(path_len + new_path_len); \ - if (req->path == NULL) \ + if (req->path == NULL) { \ + uv__req_unregister(loop, req); \ return -ENOMEM; \ + } \ req->new_path = req->path + path_len; \ memcpy((void*) req->path, path, path_len); \ memcpy((void*) req->new_path, new_path, new_path_len); \ @@ -370,20 +374,27 @@ static ssize_t uv__fs_scandir(uv_fs_t* req) { } -static ssize_t uv__fs_readlink(uv_fs_t* req) { - ssize_t len; - char* buf; +static ssize_t uv__fs_pathmax_size(const char* path) { + ssize_t pathmax; - len = pathconf(req->path, _PC_PATH_MAX); + pathmax = pathconf(path, _PC_PATH_MAX); - if (len == -1) { + if (pathmax == -1) { #if defined(PATH_MAX) - len = PATH_MAX; + return PATH_MAX; #else - len = 4096; + return 4096; #endif } + return pathmax; +} + +static ssize_t uv__fs_readlink(uv_fs_t* req) { + ssize_t len; + char* buf; + + len = uv__fs_pathmax_size(req->path); buf = uv__malloc(len + 1); if (buf == NULL) { @@ -404,6 +415,27 @@ static ssize_t uv__fs_readlink(uv_fs_t* req) { return 0; } +static ssize_t uv__fs_realpath(uv_fs_t* req) { + ssize_t len; + char* buf; + + len = uv__fs_pathmax_size(req->path); + buf = uv__malloc(len + 1); + + if (buf == NULL) { + errno = ENOMEM; + return -1; + } + + if (realpath(req->path, buf) == NULL) { + uv__free(buf); + return -1; + } + + req->ptr = buf; + + return 0; +} static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) { struct pollfd pfd; @@ -626,7 +658,9 @@ static ssize_t uv__fs_write(uv_fs_t* req) { */ #if defined(__APPLE__) static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_lock(&lock); + + if (pthread_mutex_lock(&lock)) + abort(); #endif if (req->off < 0) { @@ -683,7 +717,8 @@ static ssize_t uv__fs_write(uv_fs_t* req) { done: #if defined(__APPLE__) - pthread_mutex_unlock(&lock); + if (pthread_mutex_unlock(&lock)) + abort(); #endif return r; @@ -867,6 +902,7 @@ static void uv__fs_work(struct uv__work* w) { X(READ, uv__fs_buf_iter(req, uv__fs_read)); X(SCANDIR, uv__fs_scandir(req)); X(READLINK, uv__fs_readlink(req)); + X(REALPATH, uv__fs_realpath(req)); X(RENAME, rename(req->path, req->new_path)); X(RMDIR, rmdir(req->path)); X(SENDFILE, uv__fs_sendfile(req)); @@ -1062,8 +1098,11 @@ int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_cb cb) { INIT(MKDTEMP); req->path = uv__strdup(tpl); - if (req->path == NULL) + if (req->path == NULL) { + if (cb != NULL) + uv__req_unregister(loop, req); return -ENOMEM; + } POST; } @@ -1099,8 +1138,11 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, if (nbufs > ARRAY_SIZE(req->bufsml)) req->bufs = uv__malloc(nbufs * sizeof(*bufs)); - if (req->bufs == NULL) + if (req->bufs == NULL) { + if (cb != NULL) + uv__req_unregister(loop, req); return -ENOMEM; + } memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); @@ -1131,6 +1173,16 @@ int uv_fs_readlink(uv_loop_t* loop, } +int uv_fs_realpath(uv_loop_t* loop, + uv_fs_t* req, + const char * path, + uv_fs_cb cb) { + INIT(REALPATH); + PATH; + POST; +} + + int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, @@ -1224,8 +1276,11 @@ int uv_fs_write(uv_loop_t* loop, if (nbufs > ARRAY_SIZE(req->bufsml)) req->bufs = uv__malloc(nbufs * sizeof(*bufs)); - if (req->bufs == NULL) + if (req->bufs == NULL) { + if (cb != NULL) + uv__req_unregister(loop, req); return -ENOMEM; + } memcpy(req->bufs, bufs, nbufs * sizeof(*bufs)); diff --git a/deps/uv/src/unix/fsevents.c b/deps/uv/src/unix/fsevents.c index 8143f7c1f018db..d331a13172675e 100644 --- a/deps/uv/src/unix/fsevents.c +++ b/deps/uv/src/unix/fsevents.c @@ -73,9 +73,16 @@ typedef struct uv__fsevents_event_s uv__fsevents_event_t; typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t; typedef struct uv__cf_loop_state_s uv__cf_loop_state_t; +enum uv__cf_loop_signal_type_e { + kUVCFLoopSignalRegular, + kUVCFLoopSignalClosing +}; +typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t; + struct uv__cf_loop_signal_s { QUEUE member; uv_fs_event_t* handle; + uv__cf_loop_signal_type_t type; }; struct uv__fsevents_event_s { @@ -98,7 +105,9 @@ struct uv__cf_loop_state_s { /* Forward declarations */ static void uv__cf_loop_cb(void* arg); static void* uv__cf_loop_runner(void* arg); -static int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle); +static int uv__cf_loop_signal(uv_loop_t* loop, + uv_fs_event_t* handle, + uv__cf_loop_signal_type_t type); /* Lazy-loaded by uv__fsevents_global_init(). */ static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef, @@ -149,11 +158,7 @@ static void (*pFSEventStreamStop)(FSEventStreamRef); int err; \ uv_mutex_lock(&(handle)->cf_mutex); \ /* Split-off all events and empty original queue */ \ - QUEUE_INIT(&events); \ - if (!QUEUE_EMPTY(&(handle)->cf_events)) { \ - q = QUEUE_HEAD(&(handle)->cf_events); \ - QUEUE_SPLIT(&(handle)->cf_events, q, &events); \ - } \ + QUEUE_MOVE(&(handle)->cf_events, &events); \ /* Get error (if any) and zero original one */ \ err = (handle)->cf_error; \ (handle)->cf_error = 0; \ @@ -387,7 +392,8 @@ static void uv__fsevents_destroy_stream(uv_loop_t* loop) { /* Runs in CF thread, when there're new fsevent handles to add to stream */ -static void uv__fsevents_reschedule(uv_fs_event_t* handle) { +static void uv__fsevents_reschedule(uv_fs_event_t* handle, + uv__cf_loop_signal_type_t type) { uv__cf_loop_state_t* state; QUEUE* q; uv_fs_event_t* curr; @@ -486,7 +492,7 @@ static void uv__fsevents_reschedule(uv_fs_event_t* handle) { * * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close` */ - if (!uv__is_active(handle)) + if (type == kUVCFLoopSignalClosing) uv_sem_post(&state->fsevent_sem); } @@ -676,7 +682,7 @@ void uv__fsevents_loop_delete(uv_loop_t* loop) { if (loop->cf_state == NULL) return; - if (uv__cf_loop_signal(loop, NULL) != 0) + if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0) abort(); uv_thread_join(&loop->cf_thread); @@ -735,17 +741,14 @@ static void uv__cf_loop_cb(void* arg) { loop = arg; state = loop->cf_state; - QUEUE_INIT(&split_head); uv_mutex_lock(&loop->cf_mutex); - if (!QUEUE_EMPTY(&loop->cf_signals)) { - QUEUE* split_pos = QUEUE_HEAD(&loop->cf_signals); - QUEUE_SPLIT(&loop->cf_signals, split_pos, &split_head); - } + QUEUE_MOVE(&loop->cf_signals, &split_head); uv_mutex_unlock(&loop->cf_mutex); while (!QUEUE_EMPTY(&split_head)) { item = QUEUE_HEAD(&split_head); + QUEUE_REMOVE(item); s = QUEUE_DATA(item, uv__cf_loop_signal_t, member); @@ -753,16 +756,17 @@ static void uv__cf_loop_cb(void* arg) { if (s->handle == NULL) pCFRunLoopStop(state->loop); else - uv__fsevents_reschedule(s->handle); + uv__fsevents_reschedule(s->handle, s->type); - QUEUE_REMOVE(item); uv__free(s); } } /* Runs in UV loop to notify CF thread */ -int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle) { +int uv__cf_loop_signal(uv_loop_t* loop, + uv_fs_event_t* handle, + uv__cf_loop_signal_type_t type) { uv__cf_loop_signal_t* item; uv__cf_loop_state_t* state; @@ -771,6 +775,7 @@ int uv__cf_loop_signal(uv_loop_t* loop, uv_fs_event_t* handle) { return -ENOMEM; item->handle = handle; + item->type = type; uv_mutex_lock(&loop->cf_mutex); QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member); @@ -833,7 +838,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) { /* Reschedule FSEventStream */ assert(handle != NULL); - err = uv__cf_loop_signal(handle->loop, handle); + err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular); if (err) goto fail_loop_signal; @@ -873,7 +878,7 @@ int uv__fsevents_close(uv_fs_event_t* handle) { /* Reschedule FSEventStream */ assert(handle != NULL); - err = uv__cf_loop_signal(handle->loop, handle); + err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing); if (err) return -err; diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index e6e68283d58d07..3ff6fb15e93557 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -814,8 +814,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, return 0; *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) + if (!(*addresses)) { + freeifaddrs(addrs); return -ENOMEM; + } address = *addresses; diff --git a/deps/uv/src/unix/linux-inotify.c b/deps/uv/src/unix/linux-inotify.c index d9ed9f4b24512b..282912115d8120 100644 --- a/deps/uv/src/unix/linux-inotify.c +++ b/deps/uv/src/unix/linux-inotify.c @@ -35,6 +35,7 @@ struct watcher_list { RB_ENTRY(watcher_list) entry; QUEUE watchers; + int iterating; char* path; int wd; }; @@ -113,6 +114,15 @@ static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) { return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w); } +static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) { + /* if the watcher_list->watchers is being iterated over, we can't free it. */ + if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) { + /* No watchers left for this path. Clean up. */ + RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w); + uv__inotify_rm_watch(loop->inotify_fd, w->wd); + uv__free(w); + } +} static void uv__inotify_read(uv_loop_t* loop, uv__io_t* dummy, @@ -120,6 +130,7 @@ static void uv__inotify_read(uv_loop_t* loop, const struct uv__inotify_event* e; struct watcher_list* w; uv_fs_event_t* h; + QUEUE queue; QUEUE* q; const char* path; ssize_t size; @@ -159,10 +170,31 @@ static void uv__inotify_read(uv_loop_t* loop, */ path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path); - QUEUE_FOREACH(q, &w->watchers) { + /* We're about to iterate over the queue and call user's callbacks. + * What can go wrong? + * A callback could call uv_fs_event_stop() + * and the queue can change under our feet. + * So, we use QUEUE_MOVE() trick to safely iterate over the queue. + * And we don't free the watcher_list until we're done iterating. + * + * First, + * tell uv_fs_event_stop() (that could be called from a user's callback) + * not to free watcher_list. + */ + w->iterating = 1; + QUEUE_MOVE(&w->watchers, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); h = QUEUE_DATA(q, uv_fs_event_t, watchers); + + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&w->watchers, q); + h->cb(h, path, events, 0); } + /* done iterating, time to (maybe) free empty watcher_list */ + w->iterating = 0; + maybe_free_watcher_list(w, loop); } } } @@ -214,6 +246,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, w->wd = wd; w->path = strcpy((char*)(w + 1), path); QUEUE_INIT(&w->watchers); + w->iterating = 0; RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w); no_insert: @@ -241,12 +274,7 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { uv__handle_stop(handle); QUEUE_REMOVE(&handle->watchers); - if (QUEUE_EMPTY(&w->watchers)) { - /* No watchers left for this path. Clean up. */ - RB_REMOVE(watcher_root, CAST(&handle->loop->inotify_watchers), w); - uv__inotify_rm_watch(handle->loop->inotify_fd, w->wd); - uv__free(w); - } + maybe_free_watcher_list(w, handle->loop); return 0; } diff --git a/deps/uv/src/unix/linux-syscalls.c b/deps/uv/src/unix/linux-syscalls.c index 566e1f37cfed12..89998ded26b17c 100644 --- a/deps/uv/src/unix/linux-syscalls.c +++ b/deps/uv/src/unix/linux-syscalls.c @@ -444,18 +444,18 @@ int uv__utimesat(int dirfd, } -ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) { +ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { #if defined(__NR_preadv) - return syscall(__NR_preadv, fd, iov, iovcnt, offset); + return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32)); #else return errno = ENOSYS, -1; #endif } -ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) { +ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) { #if defined(__NR_pwritev) - return syscall(__NR_pwritev, fd, iov, iovcnt, offset); + return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32)); #else return errno = ENOSYS, -1; #endif diff --git a/deps/uv/src/unix/linux-syscalls.h b/deps/uv/src/unix/linux-syscalls.h index 6f249b72453675..96e79439cf07ab 100644 --- a/deps/uv/src/unix/linux-syscalls.h +++ b/deps/uv/src/unix/linux-syscalls.h @@ -151,8 +151,8 @@ int uv__utimesat(int dirfd, const char* path, const struct timespec times[2], int flags); -ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); -ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); +ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset); +ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset); int uv__dup3(int oldfd, int newfd, int flags); #endif /* UV_LINUX_SYSCALL_H_ */ diff --git a/deps/uv/src/unix/loop-watcher.c b/deps/uv/src/unix/loop-watcher.c index dc25760bd5344c..340bb0dfa11350 100644 --- a/deps/uv/src/unix/loop-watcher.c +++ b/deps/uv/src/unix/loop-watcher.c @@ -47,9 +47,14 @@ \ void uv__run_##name(uv_loop_t* loop) { \ uv_##name##_t* h; \ + QUEUE queue; \ QUEUE* q; \ - QUEUE_FOREACH(q, &loop->name##_handles) { \ + QUEUE_MOVE(&loop->name##_handles, &queue); \ + while (!QUEUE_EMPTY(&queue)) { \ + q = QUEUE_HEAD(&queue); \ h = QUEUE_DATA(q, uv_##name##_t, queue); \ + QUEUE_REMOVE(q); \ + QUEUE_INSERT_TAIL(&loop->name##_handles, q); \ h->name##_cb(h); \ } \ } \ diff --git a/deps/uv/src/unix/netbsd.c b/deps/uv/src/unix/netbsd.c index 29f2a4dec63831..ca48550f9d99d4 100644 --- a/deps/uv/src/unix/netbsd.c +++ b/deps/uv/src/unix/netbsd.c @@ -298,8 +298,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) + if (!(*addresses)) { + freeifaddrs(addrs); return -ENOMEM; + } address = *addresses; diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index c8d54599386efe..6a3909a666c1d0 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -161,7 +161,7 @@ char** uv_setup_args(int argc, char** argv) { int uv_set_process_title(const char* title) { - if (process_title) uv__free(process_title); + uv__free(process_title); process_title = uv__strdup(title); setproctitle(title); return 0; @@ -313,8 +313,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) + if (!(*addresses)) { + freeifaddrs(addrs); return -ENOMEM; + } address = *addresses; diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index 9fa061e6bc99b6..571f8cd778c74f 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -270,6 +270,11 @@ static void uv__write_int(int fd, int val) { } +#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)) +/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be + * avoided. Since this isn't called on those targets, the function + * doesn't even need to be defined for them. + */ static void uv__process_child_init(const uv_process_options_t* options, int stdio_count, int (*pipes)[2], @@ -375,11 +380,16 @@ static void uv__process_child_init(const uv_process_options_t* options, uv__write_int(error_fd, -errno); _exit(127); } +#endif int uv_spawn(uv_loop_t* loop, uv_process_t* process, const uv_process_options_t* options) { +#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH) + /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */ + return -ENOSYS; +#else int signal_pipe[2] = { -1, -1 }; int (*pipes)[2]; int stdio_count; @@ -528,6 +538,7 @@ int uv_spawn(uv_loop_t* loop, } return err; +#endif } diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c index 0b7a405c15da65..edd9085d3f352f 100644 --- a/deps/uv/src/unix/signal.c +++ b/deps/uv/src/unix/signal.c @@ -234,6 +234,8 @@ void uv__signal_loop_cleanup(uv_loop_t* loop) { /* Stop all the signal watchers that are still attached to this loop. This * ensures that the (shared) signal tree doesn't contain any invalid entries * entries, and that signal handlers are removed when appropriate. + * It's safe to use QUEUE_FOREACH here because the handles and the handle + * queue are not modified by uv__signal_stop(). */ QUEUE_FOREACH(q, &loop->handle_queue) { uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue); diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 183b68cf7165b0..7d7ab2633b6f2d 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -779,9 +779,9 @@ static void uv__write(uv_stream_t* stream) { if (req->send_handle) { struct msghdr msg; - char scratch[64]; struct cmsghdr *cmsg; int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle); + char scratch[64] = {0}; assert(fd_to_send >= 0); @@ -1471,7 +1471,7 @@ int uv_try_write(uv_stream_t* stream, uv__stream_osx_interrupt_select(stream); } - if (written == 0) + if (written == 0 && req_size != 0) return -EAGAIN; else return written; diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index 05b7a114031178..0c46817b446e61 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -693,8 +693,10 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) { } *addresses = uv__malloc(*count * sizeof(**addresses)); - if (!(*addresses)) + if (!(*addresses)) { + freeifaddrs(addrs); return -ENOMEM; + } address = *addresses; diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index 54c9055a08ae12..7cc5b714ed302c 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -236,6 +236,15 @@ uv_handle_type uv_guess_handle(uv_file file) { return UV_UDP; if (type == SOCK_STREAM) { +#if defined(_AIX) + /* on AIX the getsockname call returns an empty sa structure + * for sockets of type AF_UNIX. For all other types it will + * return a properly filled in structure. + */ + if (len == 0) + return UV_NAMED_PIPE; +#endif /* defined(_AIX) */ + if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) return UV_TCP; if (sa.sa_family == AF_UNIX) diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 66ecc4e341b913..39ade8de338afc 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -410,8 +410,10 @@ int uv__udp_send(uv_udp_send_t* req, if (nbufs > ARRAY_SIZE(req->bufsml)) req->bufs = uv__malloc(nbufs * sizeof(bufs[0])); - if (req->bufs == NULL) + if (req->bufs == NULL) { + uv__req_unregister(handle->loop, req); return -ENOMEM; + } memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0])); handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs); diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 675a776bf4ae1e..40ed28fec5a662 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -141,11 +141,7 @@ static const char* uv__unknown_err_code(int err) { char buf[32]; char* copy; -#ifndef _WIN32 snprintf(buf, sizeof(buf), "Unknown system error %d", err); -#else - _snprintf(buf, sizeof(buf), "Unknown system error %d", err); -#endif copy = uv__strdup(buf); return copy != NULL ? copy : "Unknown system error"; @@ -341,19 +337,25 @@ int uv_udp_recv_stop(uv_udp_t* handle) { void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { + QUEUE queue; QUEUE* q; uv_handle_t* h; - QUEUE_FOREACH(q, &loop->handle_queue) { + QUEUE_MOVE(&loop->handle_queue, &queue); + while (!QUEUE_EMPTY(&queue)) { + q = QUEUE_HEAD(&queue); h = QUEUE_DATA(q, uv_handle_t, handle_queue); + + QUEUE_REMOVE(q); + QUEUE_INSERT_TAIL(&loop->handle_queue, q); + if (h->flags & UV__HANDLE_INTERNAL) continue; walk_cb(h, arg); } } -#ifndef NDEBUG -static void uv__print_handles(uv_loop_t* loop, int only_active) { +static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) { const char* type; QUEUE* q; uv_handle_t* h; @@ -374,7 +376,7 @@ static void uv__print_handles(uv_loop_t* loop, int only_active) { default: type = ""; } - fprintf(stderr, + fprintf(stream, "[%c%c%c] %-8s %p\n", "R-"[!(h->flags & UV__HANDLE_REF)], "A-"[!(h->flags & UV__HANDLE_ACTIVE)], @@ -385,15 +387,14 @@ static void uv__print_handles(uv_loop_t* loop, int only_active) { } -void uv_print_all_handles(uv_loop_t* loop) { - uv__print_handles(loop, 0); +void uv_print_all_handles(uv_loop_t* loop, FILE* stream) { + uv__print_handles(loop, 0, stream); } -void uv_print_active_handles(uv_loop_t* loop) { - uv__print_handles(loop, 1); +void uv_print_active_handles(uv_loop_t* loop, FILE* stream) { + uv__print_handles(loop, 1, stream); } -#endif void uv_ref(uv_handle_t* handle) { diff --git a/deps/uv/src/uv-common.h b/deps/uv/src/uv-common.h index b348ec76bd50bd..27902fdf8645f7 100644 --- a/deps/uv/src/uv-common.h +++ b/deps/uv/src/uv-common.h @@ -41,6 +41,10 @@ #include "tree.h" #include "queue.h" +#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900 +extern int snprintf(char*, size_t, const char*, ...); +#endif + #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #define container_of(ptr, type, member) \ diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c index a265a272dced19..c512f35af979a3 100644 --- a/deps/uv/src/win/error.c +++ b/deps/uv/src/win/error.c @@ -129,6 +129,7 @@ int uv_translate_sys_error(int sys_errno) { case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH; case WSAENETUNREACH: return UV_ENETUNREACH; case WSAENOBUFS: return UV_ENOBUFS; + case ERROR_BAD_PATHNAME: return UV_ENOENT; case ERROR_DIRECTORY: return UV_ENOENT; case ERROR_FILE_NOT_FOUND: return UV_ENOENT; case ERROR_INVALID_NAME: return UV_ENOENT; diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index ba68f78c82a610..76ecfebaa24c39 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -381,9 +381,10 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, if (handle->dirw) { /* - * We attempt to convert the file name to its long form for - * events that still point to valid files on disk. - * For removed and renamed events, we do not provide the file name. + * We attempt to resolve the long form of the file name explicitly. + * We only do this for file names that might still exist on disk. + * If this fails, we use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. */ if (file_info->Action != FILE_ACTION_REMOVED && file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) { @@ -438,16 +439,24 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, } /* - * If we couldn't get the long name - just use the name - * provided by ReadDirectoryChangesW. + * We could not resolve the long form explicitly. + * We therefore use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. */ if (!long_filenamew) { filenamew = file_info->FileName; sizew = file_info->FileNameLength / sizeof(WCHAR); } } else { - /* Removed or renamed callbacks don't provide filename. */ - filenamew = NULL; + /* + * Removed or renamed events cannot be resolved to the long form. + * We therefore use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. + */ + if (!long_filenamew) { + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(WCHAR); + } } } else { /* We already have the long name of the file, so just use it. */ diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 4a17573113ff9b..a32b0127f7e1e9 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -110,6 +110,9 @@ const WCHAR JUNCTION_PREFIX_LEN = 4; const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\"; const WCHAR LONG_PATH_PREFIX_LEN = 4; +const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\"; +const WCHAR UNC_PATH_PREFIX_LEN = 8; + void uv_fs_init() { _fmode = _O_BINARY; @@ -233,14 +236,61 @@ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, } +static int fs__wide_to_utf8(WCHAR* w_source_ptr, + DWORD w_source_len, + char** target_ptr, + uint64_t* target_len_ptr) { + int r; + int target_len; + char* target; + target_len = WideCharToMultiByte(CP_UTF8, + 0, + w_source_ptr, + w_source_len, + NULL, + 0, + NULL, + NULL); + + if (target_len == 0) { + return -1; + } + + if (target_len_ptr != NULL) { + *target_len_ptr = target_len; + } + + if (target_ptr == NULL) { + return 0; + } + + target = uv__malloc(target_len + 1); + if (target == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } + + r = WideCharToMultiByte(CP_UTF8, + 0, + w_source_ptr, + w_source_len, + target, + target_len, + NULL, + NULL); + assert(r == target_len); + target[target_len] = '\0'; + *target_ptr = target; + return 0; +} + + INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, uint64_t* target_len_ptr) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer; - WCHAR *w_target; + WCHAR* w_target; DWORD w_target_len; - char* target; - int target_len; DWORD bytes; if (!DeviceIoControl(handle, @@ -333,50 +383,7 @@ INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr, return -1; } - /* If needed, compute the length of the target. */ - if (target_ptr != NULL || target_len_ptr != NULL) { - /* Compute the length of the target. */ - target_len = WideCharToMultiByte(CP_UTF8, - 0, - w_target, - w_target_len, - NULL, - 0, - NULL, - NULL); - if (target_len == 0) { - return -1; - } - } - - /* If requested, allocate memory and convert to UTF8. */ - if (target_ptr != NULL) { - int r; - target = (char*) uv__malloc(target_len + 1); - if (target == NULL) { - SetLastError(ERROR_OUTOFMEMORY); - return -1; - } - - r = WideCharToMultiByte(CP_UTF8, - 0, - w_target, - w_target_len, - target, - target_len, - NULL, - NULL); - assert(r == target_len); - target[target_len] = '\0'; - - *target_ptr = target; - } - - if (target_len_ptr != NULL) { - *target_len_ptr = target_len; - } - - return 0; + return fs__wide_to_utf8(w_target, w_target_len, target_ptr, target_len_ptr); } @@ -533,7 +540,15 @@ void fs__close(uv_fs_t* req) { else result = 0; - SET_REQ_RESULT(req, result); + /* _close doesn't set _doserrno on failure, but it does always set errno + * to EBADF on failure. + */ + if (result == -1) { + assert(errno == EBADF); + SET_REQ_UV_ERROR(req, UV_EBADF, ERROR_INVALID_HANDLE); + } else { + req->result = 0; + } } @@ -1699,6 +1714,84 @@ static void fs__readlink(uv_fs_t* req) { } +static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) { + int r; + DWORD w_realpath_len; + WCHAR* w_realpath_ptr; + WCHAR* w_finalpath_ptr = NULL; + + w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS); + if (w_realpath_len == 0) { + return -1; + } + + w_realpath_ptr = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR)); + if (w_realpath_ptr == NULL) { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } + + if (pGetFinalPathNameByHandleW(handle, + w_realpath_ptr, + w_realpath_len, + VOLUME_NAME_DOS) == 0) { + uv__free(w_realpath_ptr); + SetLastError(ERROR_INVALID_HANDLE); + return -1; + } + + /* convert UNC path to long path */ + if (wcsncmp(w_realpath_ptr, + UNC_PATH_PREFIX, + UNC_PATH_PREFIX_LEN) == 0) { + w_finalpath_ptr = w_realpath_ptr + 6; + *w_finalpath_ptr = L'\\'; + } else if (wcsncmp(w_realpath_ptr, + LONG_PATH_PREFIX, + LONG_PATH_PREFIX_LEN) == 0) { + w_finalpath_ptr = w_realpath_ptr + 4; + } else { + uv__free(w_realpath_ptr); + SetLastError(ERROR_INVALID_HANDLE); + return -1; + } + + r = fs__wide_to_utf8(w_finalpath_ptr, w_realpath_len, realpath_ptr, NULL); + uv__free(w_realpath_ptr); + return r; +} + +static void fs__realpath(uv_fs_t* req) { + HANDLE handle; + + if (!pGetFinalPathNameByHandleW) { + SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); + return; + } + + handle = CreateFileW(req->file.pathw, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) { + CloseHandle(handle); + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + CloseHandle(handle); + req->flags |= UV_FS_FREE_PTR; + SET_REQ_RESULT(req, 0); +} + static void fs__chown(uv_fs_t* req) { req->result = 0; @@ -1743,6 +1836,7 @@ static void uv__fs_work(struct uv__work* w) { XX(LINK, link) XX(SYMLINK, symlink) XX(READLINK, readlink) + XX(REALPATH, realpath) XX(CHOWN, chown) XX(FCHOWN, fchown); default: @@ -2067,6 +2161,31 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, } +int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path, + uv_fs_cb cb) { + int err; + + if (!req || !path) { + return UV_EINVAL; + } + + uv_fs_req_init(loop, req, UV_FS_REALPATH, cb); + + err = fs__capture_path(req, path, NULL, cb != NULL); + if (err) { + return uv_translate_sys_error(err); + } + + if (cb) { + QUEUE_FS_TP_JOB(loop, req); + return 0; + } else { + fs__realpath(req); + return req->result; + } +} + + int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb) { int err; diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c index 3d23660e884c5d..ceed3b7638b457 100644 --- a/deps/uv/src/win/getaddrinfo.c +++ b/deps/uv/src/win/getaddrinfo.c @@ -109,10 +109,8 @@ static void uv__getaddrinfo_done(struct uv__work* w, int status) { req = container_of(w, uv_getaddrinfo_t, work_req); /* release input parameter memory */ - if (req->alloc != NULL) { - uv__free(req->alloc); - req->alloc = NULL; - } + uv__free(req->alloc); + req->alloc = NULL; if (status == UV_ECANCELED) { assert(req->retcode == 0); @@ -219,9 +217,7 @@ void uv_freeaddrinfo(struct addrinfo* ai) { char* alloc_ptr = (char*)ai; /* release copied result memory */ - if (alloc_ptr != NULL) { - uv__free(alloc_ptr); - } + uv__free(alloc_ptr); } @@ -354,8 +350,9 @@ int uv_getaddrinfo(uv_loop_t* loop, } error: - if (req != NULL && req->alloc != NULL) { + if (req != NULL) { uv__free(req->alloc); + req->alloc = NULL; } return uv_translate_sys_error(err); } diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 8d4081bdb51ccf..783f21af0fe9f1 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -327,6 +327,7 @@ void uv__util_init(); uint64_t uv__hrtime(double scale); int uv_parent_pid(); +int uv_current_pid(); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 8312b1ceb958c3..bcce80c77e5d57 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -85,7 +85,7 @@ static void eof_timer_close_cb(uv_handle_t* handle); static void uv_unique_pipe_name(char* ptr, char* name, size_t size) { - _snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId()); + snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%u", ptr, GetCurrentProcessId()); } @@ -1246,6 +1246,10 @@ static int uv_pipe_write_impl(uv_loop_t* loop, if (send_handle) { tcp_send_handle = (uv_tcp_t*)send_handle; + if (handle->pipe.conn.ipc_pid == 0) { + handle->pipe.conn.ipc_pid = uv_current_pid(); + } + err = uv_tcp_duplicate_socket(tcp_send_handle, handle->pipe.conn.ipc_pid, &ipc_frame.socket_info_ex.socket_info); if (err) { @@ -1629,7 +1633,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle, if (ReadFile(handle->handle, buf.base, - buf.len, + min(buf.len, avail), &bytes, NULL)) { /* Successful read */ diff --git a/deps/uv/src/win/snprintf.c b/deps/uv/src/win/snprintf.c new file mode 100644 index 00000000000000..776c0e39217585 --- /dev/null +++ b/deps/uv/src/win/snprintf.c @@ -0,0 +1,42 @@ +/* Copyright the libuv project 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. + */ + +#if defined(_MSC_VER) && _MSC_VER < 1900 + +#include +#include + +/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer + * on overflow... + */ +int snprintf(char* buf, size_t len, const char* fmt, ...) { + int n; + va_list ap; + va_start(ap, fmt); + + n = _vscprintf(fmt, ap); + vsnprintf_s(buf, len, _TRUNCATE, fmt, ap); + + va_end(ap); + return n; +} + +#endif diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index b40bb42710ae7b..d87cc699097cf7 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -208,7 +208,7 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) { static int style_captured = 0; /* Only do this once. - /* Assumption: Caller has acquired uv_tty_output_lock. */ + Assumption: Caller has acquired uv_tty_output_lock. */ if (style_captured) return; diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index a0d1307f8a2590..cb247513046351 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -59,6 +59,10 @@ static char *process_title; static CRITICAL_SECTION process_title_lock; +/* Cached copy of the process id, written once. */ +static DWORD current_pid = 0; + + /* Interval (in seconds) of the high-resolution clock. */ static double hrtime_interval_ = 0; @@ -359,6 +363,14 @@ int uv_parent_pid() { } +int uv_current_pid() { + if (current_pid == 0) { + current_pid = GetCurrentProcessId(); + } + return current_pid; +} + + char** uv_setup_args(int argc, char** argv) { return argv; } diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index b0b7fd825fb64e..26bd0648668742 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/src/win/winapi.c @@ -46,6 +46,7 @@ sSleepConditionVariableSRW pSleepConditionVariableSRW; sWakeAllConditionVariable pWakeAllConditionVariable; sWakeConditionVariable pWakeConditionVariable; sCancelSynchronousIo pCancelSynchronousIo; +sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; void uv_winapi_init() { @@ -139,4 +140,7 @@ void uv_winapi_init() { pCancelSynchronousIo = (sCancelSynchronousIo) GetProcAddress(kernel32_module, "CancelSynchronousIo"); + + pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW) + GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW"); } diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index 5bc79bcab27dbb..122198a6d481ac 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4678,6 +4678,12 @@ typedef VOID (WINAPI* sWakeConditionVariable) typedef BOOL (WINAPI* sCancelSynchronousIo) (HANDLE hThread); +typedef DWORD (WINAPI* sGetFinalPathNameByHandleW) + (HANDLE hFile, + LPWSTR lpszFilePath, + DWORD cchFilePath, + DWORD dwFlags); + /* Ntdll function pointers */ extern sRtlNtStatusToDosError pRtlNtStatusToDosError; extern sNtDeviceIoControlFile pNtDeviceIoControlFile; @@ -4699,5 +4705,6 @@ extern sSleepConditionVariableSRW pSleepConditionVariableSRW; extern sWakeAllConditionVariable pWakeAllConditionVariable; extern sWakeConditionVariable pWakeConditionVariable; extern sCancelSynchronousIo pCancelSynchronousIo; +extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW; #endif /* UV_WIN_WINAPI_H_ */ diff --git a/deps/uv/test/runner-win.h b/deps/uv/test/runner-win.h index c94b89bd5ec712..8cc4c16eb22eac 100644 --- a/deps/uv/test/runner-win.h +++ b/deps/uv/test/runner-win.h @@ -19,9 +19,6 @@ * IN THE SOFTWARE. */ -/* Don't complain about _snprintf being insecure. */ -#define _CRT_SECURE_NO_WARNINGS - /* Don't complain about write(), fileno() etc. being deprecated. */ #pragma warning(disable : 4996) @@ -30,10 +27,9 @@ #include #include - -/* Windows has no snprintf, only _snprintf. */ -#define snprintf _snprintf - +#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900 +extern int snprintf(char*, size_t, const char*, ...); +#endif typedef struct { HANDLE process; diff --git a/deps/uv/test/runner.c b/deps/uv/test/runner.c index e094defc7e7de5..c616d176445db1 100644 --- a/deps/uv/test/runner.c +++ b/deps/uv/test/runner.c @@ -210,6 +210,8 @@ int run_test(const char* test, #ifndef _WIN32 /* Clean up stale socket from previous run. */ remove(TEST_PIPENAME); + remove(TEST_PIPENAME_2); + remove(TEST_PIPENAME_3); #endif /* If it's a helper the user asks for, start it directly. */ diff --git a/deps/uv/test/task.h b/deps/uv/test/task.h index e736763802f610..d18c1daa364702 100644 --- a/deps/uv/test/task.h +++ b/deps/uv/test/task.h @@ -50,9 +50,11 @@ #ifdef _WIN32 # define TEST_PIPENAME "\\\\?\\pipe\\uv-test" # define TEST_PIPENAME_2 "\\\\?\\pipe\\uv-test2" +# define TEST_PIPENAME_3 "\\\\?\\pipe\\uv-test3" #else # define TEST_PIPENAME "/tmp/uv-test-sock" # define TEST_PIPENAME_2 "/tmp/uv-test-sock2" +# define TEST_PIPENAME_3 "/tmp/uv-test-sock3" #endif #ifdef _WIN32 @@ -174,40 +176,8 @@ enum test_status { #endif - -#if defined _WIN32 && ! defined __GNUC__ - -#include - -/* Define inline for MSVC<2015 */ -# if defined(_MSC_VER) && _MSC_VER < 1900 -# define inline __inline -# endif - -# if defined(_MSC_VER) && _MSC_VER < 1900 -/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer - * on overflow... - */ -inline int snprintf(char* buf, size_t len, const char* fmt, ...) { - va_list ap; - int n; - - va_start(ap, fmt); - n = _vsprintf_p(buf, len, fmt, ap); - va_end(ap); - - /* It's a sad fact of life that no one ever checks the return value of - * snprintf(). Zero-terminating the buffer hopefully reduces the risk - * of gaping security holes. - */ - if (n < 0) - if (len > 0) - buf[0] = '\0'; - - return n; -} -# endif - +#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900 +extern int snprintf(char*, size_t, const char*, ...); #endif #if defined(__clang__) || \ diff --git a/deps/uv/test/test-emfile.c b/deps/uv/test/test-emfile.c index 453bfe4cf5ff55..dd35f785b46352 100644 --- a/deps/uv/test/test-emfile.c +++ b/deps/uv/test/test-emfile.c @@ -25,7 +25,6 @@ #include "task.h" #include -#include #include #include @@ -45,6 +44,13 @@ TEST_IMPL(emfile) { uv_loop_t* loop; int first_fd; + /* Lower the file descriptor limit and use up all fds save one. */ + limits.rlim_cur = limits.rlim_max = maxfd + 1; + if (setrlimit(RLIMIT_NOFILE, &limits)) { + ASSERT(errno == EPERM); /* Valgrind blocks the setrlimit() call. */ + RETURN_SKIP("setrlimit(RLIMIT_NOFILE) failed, running under valgrind?"); + } + loop = uv_default_loop(); ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); ASSERT(0 == uv_tcp_init(loop, &server_handle)); @@ -52,13 +58,6 @@ TEST_IMPL(emfile) { ASSERT(0 == uv_tcp_bind(&server_handle, (const struct sockaddr*) &addr, 0)); ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 8, connection_cb)); - /* Lower the file descriptor limit and use up all fds save one. */ - limits.rlim_cur = limits.rlim_max = maxfd + 1; - if (setrlimit(RLIMIT_NOFILE, &limits)) { - perror("setrlimit(RLIMIT_NOFILE)"); - ASSERT(0); - } - /* Remember the first one so we can clean up afterwards. */ do first_fd = dup(0); diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index a0908ce575bd42..e02ff2fda5e5d9 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -115,7 +115,11 @@ static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename, ASSERT(handle == &fs_event); ASSERT(status == 0); ASSERT(events == UV_RENAME); + #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) + ASSERT(strcmp(filename, "file1") == 0); + #else ASSERT(filename == NULL || strcmp(filename, "file1") == 0); + #endif ASSERT(0 == uv_fs_event_stop(handle)); uv_close((uv_handle_t*)handle, close_cb); } @@ -178,8 +182,12 @@ static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle, ASSERT(handle == &fs_event); ASSERT(status == 0); ASSERT(events == UV_CHANGE || UV_RENAME); + #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) + ASSERT(strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0); + #else ASSERT(filename == NULL || strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0); + #endif if (fs_event_created + fs_event_removed == fs_event_file_count) { /* Once we've processed all create events, delete all files */ @@ -250,8 +258,16 @@ static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle, ASSERT(handle == &fs_event); ASSERT(status == 0); ASSERT(events == UV_CHANGE || UV_RENAME); + #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) + ASSERT(strncmp(filename, + file_prefix_in_subdir, + sizeof(file_prefix_in_subdir) - 1) == 0); + #else ASSERT(filename == NULL || - strncmp(filename, file_prefix_in_subdir, sizeof(file_prefix_in_subdir) - 1) == 0); + strncmp(filename, + file_prefix_in_subdir, + sizeof(file_prefix_in_subdir) - 1) == 0); + #endif if (fs_event_created + fs_event_removed == fs_event_file_count) { /* Once we've processed all create events, delete all files */ @@ -270,7 +286,11 @@ static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename, ASSERT(handle == &fs_event); ASSERT(status == 0); ASSERT(events == UV_CHANGE); + #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) + ASSERT(strcmp(filename, "file2") == 0); + #else ASSERT(filename == NULL || strcmp(filename, "file2") == 0); + #endif ASSERT(0 == uv_fs_event_stop(handle)); uv_close((uv_handle_t*)handle, close_cb); } @@ -293,7 +313,11 @@ static void fs_event_cb_file_current_dir(uv_fs_event_t* handle, ASSERT(handle == &fs_event); ASSERT(status == 0); ASSERT(events == UV_CHANGE); + #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__) + ASSERT(strcmp(filename, "watch_file") == 0); + #else ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0); + #endif /* Regression test for SunOS: touch should generate just one event. */ { @@ -487,7 +511,7 @@ TEST_IMPL(fs_event_watch_file_current_dir) { r = uv_timer_init(loop, &timer); ASSERT(r == 0); - r = uv_timer_start(&timer, timer_cb_touch, 1, 0); + r = uv_timer_start(&timer, timer_cb_touch, 10, 0); ASSERT(r == 0); ASSERT(timer_cb_touch_called == 0); diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index 90572ca6147150..cf37ac4909ca12 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -83,6 +83,7 @@ static int fchown_cb_count; static int link_cb_count; static int symlink_cb_count; static int readlink_cb_count; +static int realpath_cb_count; static int utime_cb_count; static int futime_cb_count; @@ -168,6 +169,35 @@ static void readlink_cb(uv_fs_t* req) { } +static void realpath_cb(uv_fs_t* req) { + char test_file_abs_buf[PATHMAX]; + size_t test_file_abs_size = sizeof(test_file_abs_buf); + ASSERT(req->fs_type == UV_FS_REALPATH); +#ifdef _WIN32 + /* + * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() + */ + if (req->result == UV_ENOSYS) { + realpath_cb_count++; + uv_fs_req_cleanup(req); + return; + } +#endif + ASSERT(req->result == 0); + + uv_cwd(test_file_abs_buf, &test_file_abs_size); +#ifdef _WIN32 + strcat(test_file_abs_buf, "\\test_file"); + ASSERT(stricmp(req->ptr, test_file_abs_buf) == 0); +#else + strcat(test_file_abs_buf, "/test_file"); + ASSERT(strcmp(req->ptr, test_file_abs_buf) == 0); +#endif + realpath_cb_count++; + uv_fs_req_cleanup(req); +} + + static void access_cb(uv_fs_t* req) { ASSERT(req->fs_type == UV_FS_ACCESS); access_cb_count++; @@ -1565,11 +1595,43 @@ TEST_IMPL(fs_readlink) { } +TEST_IMPL(fs_realpath) { + uv_fs_t req; + + loop = uv_default_loop(); + ASSERT(0 == uv_fs_realpath(loop, &req, "no_such_file", dummy_cb)); + ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); + ASSERT(dummy_cb_count == 1); + ASSERT(req.ptr == NULL); +#ifdef _WIN32 + /* + * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() + */ + if (req.result == UV_ENOSYS) { + uv_fs_req_cleanup(&req); + RETURN_SKIP("realpath is not supported on Windows XP"); + } +#endif + ASSERT(req.result == UV_ENOENT); + uv_fs_req_cleanup(&req); + + ASSERT(UV_ENOENT == uv_fs_realpath(NULL, &req, "no_such_file", NULL)); + ASSERT(req.ptr == NULL); + ASSERT(req.result == UV_ENOENT); + uv_fs_req_cleanup(&req); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + TEST_IMPL(fs_symlink) { int r; uv_fs_t req; uv_file file; uv_file link; + char test_file_abs_buf[PATHMAX]; + size_t test_file_abs_size; /* Setup. */ unlink("test_file"); @@ -1577,6 +1639,14 @@ TEST_IMPL(fs_symlink) { unlink("test_file_symlink2"); unlink("test_file_symlink_symlink"); unlink("test_file_symlink2_symlink"); + test_file_abs_size = sizeof(test_file_abs_buf); +#ifdef _WIN32 + uv_cwd(test_file_abs_buf, &test_file_abs_size); + strcat(test_file_abs_buf, "\\test_file"); +#else + uv_cwd(test_file_abs_buf, &test_file_abs_size); + strcat(test_file_abs_buf, "/test_file"); +#endif loop = uv_default_loop(); @@ -1647,6 +1717,24 @@ TEST_IMPL(fs_symlink) { ASSERT(strcmp(req.ptr, "test_file_symlink") == 0); uv_fs_req_cleanup(&req); + r = uv_fs_realpath(NULL, &req, "test_file_symlink_symlink", NULL); +#ifdef _WIN32 + /* + * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() + */ + if (r == UV_ENOSYS) { + uv_fs_req_cleanup(&req); + RETURN_SKIP("realpath is not supported on Windows XP"); + } +#endif + ASSERT(r == 0); +#ifdef _WIN32 + ASSERT(stricmp(req.ptr, test_file_abs_buf) == 0); +#else + ASSERT(strcmp(req.ptr, test_file_abs_buf) == 0); +#endif + uv_fs_req_cleanup(&req); + /* async link */ r = uv_fs_symlink(loop, &req, @@ -1687,6 +1775,20 @@ TEST_IMPL(fs_symlink) { uv_run(loop, UV_RUN_DEFAULT); ASSERT(readlink_cb_count == 1); + r = uv_fs_realpath(loop, &req, "test_file", realpath_cb); +#ifdef _WIN32 + /* + * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() + */ + if (r == UV_ENOSYS) { + uv_fs_req_cleanup(&req); + RETURN_SKIP("realpath is not supported on Windows XP"); + } +#endif + ASSERT(r == 0); + uv_run(loop, UV_RUN_DEFAULT); + ASSERT(realpath_cb_count == 1); + /* * Run the loop just to check we don't have make any extraneous uv_ref() * calls. This should drop out immediately. @@ -1710,12 +1812,15 @@ TEST_IMPL(fs_symlink_dir) { int r; char* test_dir; uv_dirent_t dent; + static char test_dir_abs_buf[PATHMAX]; + size_t test_dir_abs_size; /* set-up */ unlink("test_dir/file1"); unlink("test_dir/file2"); rmdir("test_dir"); rmdir("test_dir_symlink"); + test_dir_abs_size = sizeof(test_dir_abs_buf); loop = uv_default_loop(); @@ -1723,16 +1828,16 @@ TEST_IMPL(fs_symlink_dir) { uv_fs_req_cleanup(&req); #ifdef _WIN32 - { - static char src_path_buf[PATHMAX]; - size_t size; - size = sizeof(src_path_buf); - strcpy(src_path_buf, "\\\\?\\"); - uv_cwd(src_path_buf + 4, &size); - strcat(src_path_buf, "\\test_dir\\"); - test_dir = src_path_buf; - } + strcpy(test_dir_abs_buf, "\\\\?\\"); + uv_cwd(test_dir_abs_buf + 4, &test_dir_abs_size); + test_dir_abs_size += 4; + strcat(test_dir_abs_buf, "\\test_dir\\"); + test_dir_abs_size += strlen("\\test_dir\\"); + test_dir = test_dir_abs_buf; #else + uv_cwd(test_dir_abs_buf, &test_dir_abs_size); + strcat(test_dir_abs_buf, "/test_dir"); + test_dir_abs_size += strlen("/test_dir"); test_dir = "test_dir"; #endif @@ -1767,6 +1872,25 @@ TEST_IMPL(fs_symlink_dir) { #endif uv_fs_req_cleanup(&req); + r = uv_fs_realpath(NULL, &req, "test_dir_symlink", NULL); +#ifdef _WIN32 + /* + * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW() + */ + if (r == UV_ENOSYS) { + uv_fs_req_cleanup(&req); + RETURN_SKIP("realpath is not supported on Windows XP"); + } +#endif + ASSERT(r == 0); +#ifdef _WIN32 + ASSERT(strlen(req.ptr) == test_dir_abs_size - 5); + ASSERT(strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5) == 0); +#else + ASSERT(strcmp(req.ptr, test_dir_abs_buf) == 0); +#endif + uv_fs_req_cleanup(&req); + r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); ASSERT(r >= 0); diff --git a/deps/uv/test/test-get-loadavg.c b/deps/uv/test/test-get-loadavg.c index 7465e18b91e9c7..4762e47576d064 100644 --- a/deps/uv/test/test-get-loadavg.c +++ b/deps/uv/test/test-get-loadavg.c @@ -24,10 +24,9 @@ TEST_IMPL(get_loadavg) { - double avg[3]; + double avg[3] = {-1, -1, -1}; uv_loadavg(avg); - ASSERT(avg != NULL); ASSERT(avg[0] >= 0); ASSERT(avg[1] >= 0); ASSERT(avg[2] >= 0); diff --git a/deps/uv/test/test-getaddrinfo.c b/deps/uv/test/test-getaddrinfo.c index 45813c313af2c2..6b644a8d442a3a 100644 --- a/deps/uv/test/test-getaddrinfo.c +++ b/deps/uv/test/test-getaddrinfo.c @@ -83,10 +83,11 @@ static void getaddrinfo_cuncurrent_cb(uv_getaddrinfo_t* handle, TEST_IMPL(getaddrinfo_fail) { uv_getaddrinfo_t req; + /* Use a FQDN by ending in a period */ ASSERT(0 == uv_getaddrinfo(uv_default_loop(), &req, getaddrinfo_fail_cb, - "xyzzy.xyzzy.xyzzy", + "xyzzy.xyzzy.xyzzy.", NULL, NULL)); ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); @@ -100,10 +101,11 @@ TEST_IMPL(getaddrinfo_fail) { TEST_IMPL(getaddrinfo_fail_sync) { uv_getaddrinfo_t req; + /* Use a FQDN by ending in a period */ ASSERT(0 > uv_getaddrinfo(uv_default_loop(), &req, NULL, - "xyzzy.xyzzy.xyzzy", + "xyzzy.xyzzy.xyzzy.", NULL, NULL)); uv_freeaddrinfo(req.addrinfo); diff --git a/deps/uv/test/test-getnameinfo.c b/deps/uv/test/test-getnameinfo.c index ebe9246699dbd0..b1391616d13e54 100644 --- a/deps/uv/test/test-getnameinfo.c +++ b/deps/uv/test/test-getnameinfo.c @@ -73,8 +73,8 @@ TEST_IMPL(getnameinfo_basic_ip4_sync) { NULL, (const struct sockaddr*)&addr4, 0)); - ASSERT(req.host != NULL); - ASSERT(req.service != NULL); + ASSERT(req.host[0] != '\0'); + ASSERT(req.service[0] != '\0'); MAKE_VALGRIND_HAPPY(); return 0; diff --git a/deps/uv/test/test-ipc-send-recv.c b/deps/uv/test/test-ipc-send-recv.c index d9b913339d3d50..c445483fa089e3 100644 --- a/deps/uv/test/test-ipc-send-recv.c +++ b/deps/uv/test/test-ipc-send-recv.c @@ -30,6 +30,8 @@ void spawn_helper(uv_pipe_t* channel, uv_process_t* process, const char* helper); +void ipc_send_recv_helper_threadproc(void* arg); + union handles { uv_handle_t handle; uv_stream_t stream; @@ -38,16 +40,37 @@ union handles { uv_tty_t tty; }; -struct echo_ctx { +struct test_ctx { uv_pipe_t channel; + uv_connect_t connect_req; uv_write_t write_req; + uv_write_t write_req2; uv_handle_type expected_type; union handles send; + union handles send2; + union handles recv; + union handles recv2; +}; + +struct echo_ctx { + uv_pipe_t listen; + uv_pipe_t channel; + uv_write_t write_req; + uv_write_t write_req2; + uv_handle_type expected_type; union handles recv; + union handles recv2; }; -static struct echo_ctx ctx; -static int num_recv_handles; +static struct test_ctx ctx; +static struct echo_ctx ctx2; + +/* Used in write2_cb to decide if we need to cleanup or not */ +static int is_child_process; +static int is_in_process; +static int read_cb_called; +static int recv_cb_called; +static int write2_cb_called; static void alloc_cb(uv_handle_t* handle, @@ -66,39 +89,55 @@ static void recv_cb(uv_stream_t* handle, uv_handle_type pending; uv_pipe_t* pipe; int r; + union handles* recv; + + if (++recv_cb_called == 1) { + recv = &ctx.recv; + } else { + recv = &ctx.recv2; + } pipe = (uv_pipe_t*) handle; ASSERT(pipe == &ctx.channel); - ASSERT(nread >= 0); - ASSERT(1 == uv_pipe_pending_count(pipe)); - - pending = uv_pipe_pending_type(pipe); - ASSERT(pending == ctx.expected_type); - - if (pending == UV_NAMED_PIPE) - r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0); - else if (pending == UV_TCP) - r = uv_tcp_init(ctx.channel.loop, &ctx.recv.tcp); - else - abort(); - ASSERT(r == 0); - r = uv_accept(handle, &ctx.recv.stream); - ASSERT(r == 0); - - uv_close((uv_handle_t*)&ctx.channel, NULL); - uv_close(&ctx.send.handle, NULL); - uv_close(&ctx.recv.handle, NULL); - num_recv_handles++; + /* Depending on the OS, the final recv_cb can be called after the child + * process has terminated which can result in nread being UV_EOF instead of + * the number of bytes read. Since the other end of the pipe has closed this + * UV_EOF is an acceptable value. */ + if (nread == UV_EOF) { + /* UV_EOF is only acceptable for the final recv_cb call */ + ASSERT(recv_cb_called == 2); + } else { + ASSERT(nread >= 0); + ASSERT(1 == uv_pipe_pending_count(pipe)); + + pending = uv_pipe_pending_type(pipe); + ASSERT(pending == ctx.expected_type); + + if (pending == UV_NAMED_PIPE) + r = uv_pipe_init(ctx.channel.loop, &recv->pipe, 0); + else if (pending == UV_TCP) + r = uv_tcp_init(ctx.channel.loop, &recv->tcp); + else + abort(); + ASSERT(r == 0); + + r = uv_accept(handle, &recv->stream); + ASSERT(r == 0); + } + + /* Close after two writes received */ + if (recv_cb_called == 2) { + uv_close((uv_handle_t*)&ctx.channel, NULL); + } } - -static int run_test(void) { - uv_process_t process; - uv_buf_t buf; +static void connect_cb(uv_connect_t* req, int status) { int r; + uv_buf_t buf; - spawn_helper(&ctx.channel, &process, "ipc_send_recv_helper"); + ASSERT(req == &ctx.connect_req); + ASSERT(status == 0); buf = uv_buf_init(".", 1); r = uv_write2(&ctx.write_req, @@ -108,19 +147,56 @@ static int run_test(void) { NULL); ASSERT(r == 0); + /* Perform two writes to the same pipe to make sure that on Windows we are + * not running into issue 505: + * https://github.com/libuv/libuv/issues/505 */ + buf = uv_buf_init(".", 1); + r = uv_write2(&ctx.write_req2, + (uv_stream_t*)&ctx.channel, + &buf, 1, + &ctx.send2.stream, + NULL); + ASSERT(r == 0); + r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb); ASSERT(r == 0); +} + +static int run_test(int inprocess) { + uv_process_t process; + uv_thread_t tid; + int r; + + if (inprocess) { + r = uv_thread_create(&tid, ipc_send_recv_helper_threadproc, (void *) 42); + ASSERT(r == 0); + + uv_sleep(1000); + + r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1); + ASSERT(r == 0); + + uv_pipe_connect(&ctx.connect_req, &ctx.channel, TEST_PIPENAME_3, connect_cb); + } else { + spawn_helper(&ctx.channel, &process, "ipc_send_recv_helper"); + + connect_cb(&ctx.connect_req, 0); + } r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(r == 0); - ASSERT(num_recv_handles == 1); + ASSERT(recv_cb_called == 2); + + if (inprocess) { + r = uv_thread_join(&tid); + ASSERT(r == 0); + } return 0; } - -TEST_IMPL(ipc_send_recv_pipe) { +static int run_ipc_send_recv_pipe(int inprocess) { int r; ctx.expected_type = UV_NAMED_PIPE; @@ -131,15 +207,28 @@ TEST_IMPL(ipc_send_recv_pipe) { r = uv_pipe_bind(&ctx.send.pipe, TEST_PIPENAME); ASSERT(r == 0); - r = run_test(); + r = uv_pipe_init(uv_default_loop(), &ctx.send2.pipe, 1); + ASSERT(r == 0); + + r = uv_pipe_bind(&ctx.send2.pipe, TEST_PIPENAME_2); + ASSERT(r == 0); + + r = run_test(inprocess); ASSERT(r == 0); MAKE_VALGRIND_HAPPY(); return 0; } +TEST_IMPL(ipc_send_recv_pipe) { + return run_ipc_send_recv_pipe(0); +} -TEST_IMPL(ipc_send_recv_tcp) { +TEST_IMPL(ipc_send_recv_pipe_inprocess) { + return run_ipc_send_recv_pipe(1); +} + +static int run_ipc_send_recv_tcp(int inprocess) { struct sockaddr_in addr; int r; @@ -150,25 +239,45 @@ TEST_IMPL(ipc_send_recv_tcp) { r = uv_tcp_init(uv_default_loop(), &ctx.send.tcp); ASSERT(r == 0); + r = uv_tcp_init(uv_default_loop(), &ctx.send2.tcp); + ASSERT(r == 0); + r = uv_tcp_bind(&ctx.send.tcp, (const struct sockaddr*) &addr, 0); ASSERT(r == 0); - r = run_test(); + r = uv_tcp_bind(&ctx.send2.tcp, (const struct sockaddr*) &addr, 0); + ASSERT(r == 0); + + r = run_test(inprocess); ASSERT(r == 0); MAKE_VALGRIND_HAPPY(); return 0; } +TEST_IMPL(ipc_send_recv_tcp) { + return run_ipc_send_recv_tcp(0); +} + +TEST_IMPL(ipc_send_recv_tcp_inprocess) { + return run_ipc_send_recv_tcp(1); +} + -/* Everything here runs in a child process. */ +/* Everything here runs in a child process or second thread. */ static void write2_cb(uv_write_t* req, int status) { ASSERT(status == 0); - uv_close(&ctx.recv.handle, NULL); - uv_close((uv_handle_t*)&ctx.channel, NULL); -} + /* After two successful writes in the child process, allow the child + * process to be closed. */ + if (++write2_cb_called == 2 && (is_child_process || is_in_process)) { + uv_close(&ctx2.recv.handle, NULL); + uv_close(&ctx2.recv2.handle, NULL); + uv_close((uv_handle_t*)&ctx2.channel, NULL); + uv_close((uv_handle_t*)&ctx2.listen, NULL); + } +} static void read_cb(uv_stream_t* handle, ssize_t nread, @@ -177,37 +286,102 @@ static void read_cb(uv_stream_t* handle, uv_pipe_t* pipe; uv_handle_type pending; int r; + union handles* recv; + uv_write_t* write_req; + + if (nread == UV__EOF || nread == UV__ECONNABORTED) { + return; + } + + if (++read_cb_called == 2) { + recv = &ctx2.recv; + write_req = &ctx2.write_req; + } else { + recv = &ctx2.recv2; + write_req = &ctx2.write_req2; + } pipe = (uv_pipe_t*) handle; - ASSERT(pipe == &ctx.channel); + ASSERT(pipe == &ctx2.channel); ASSERT(nread >= 0); ASSERT(1 == uv_pipe_pending_count(pipe)); pending = uv_pipe_pending_type(pipe); ASSERT(pending == UV_NAMED_PIPE || pending == UV_TCP); - wrbuf = uv_buf_init(".", 1); - if (pending == UV_NAMED_PIPE) - r = uv_pipe_init(ctx.channel.loop, &ctx.recv.pipe, 0); + r = uv_pipe_init(ctx2.channel.loop, &recv->pipe, 0); else if (pending == UV_TCP) - r = uv_tcp_init(ctx.channel.loop, &ctx.recv.tcp); + r = uv_tcp_init(ctx2.channel.loop, &recv->tcp); else abort(); ASSERT(r == 0); - r = uv_accept(handle, &ctx.recv.stream); + r = uv_accept(handle, &recv->stream); ASSERT(r == 0); - r = uv_write2(&ctx.write_req, - (uv_stream_t*)&ctx.channel, + wrbuf = uv_buf_init(".", 1); + r = uv_write2(write_req, + (uv_stream_t*)&ctx2.channel, &wrbuf, 1, - &ctx.recv.stream, + &recv->stream, write2_cb); ASSERT(r == 0); } +static void send_recv_start() { + int r; + ASSERT(1 == uv_is_readable((uv_stream_t*)&ctx2.channel)); + ASSERT(1 == uv_is_writable((uv_stream_t*)&ctx2.channel)); + ASSERT(0 == uv_is_closing((uv_handle_t*)&ctx2.channel)); + + r = uv_read_start((uv_stream_t*)&ctx2.channel, alloc_cb, read_cb); + ASSERT(r == 0); +} + +static void listen_cb(uv_stream_t* handle, int status) { + int r; + ASSERT(handle == (uv_stream_t*)&ctx2.listen); + ASSERT(status == 0); + + r = uv_accept((uv_stream_t*)&ctx2.listen, (uv_stream_t*)&ctx2.channel); + ASSERT(r == 0); + + send_recv_start(); +} + +int run_ipc_send_recv_helper(uv_loop_t* loop, int inprocess) { + int r; + + is_in_process = inprocess; + + memset(&ctx2, 0, sizeof(ctx2)); + + r = uv_pipe_init(loop, &ctx2.listen, 0); + ASSERT(r == 0); + + r = uv_pipe_init(loop, &ctx2.channel, 1); + ASSERT(r == 0); + + if (inprocess) { + r = uv_pipe_bind(&ctx2.listen, TEST_PIPENAME_3); + ASSERT(r == 0); + + r = uv_listen((uv_stream_t*)&ctx2.listen, SOMAXCONN, listen_cb); + ASSERT(r == 0); + } else { + r = uv_pipe_open(&ctx2.channel, 0); + ASSERT(r == 0); + + send_recv_start(); + } + + r = uv_run(loop, UV_RUN_DEFAULT); + ASSERT(r == 0); + + return 0; +} /* stdin is a duplex channel over which a handle is sent. * We receive it and send it back where it came from. @@ -215,22 +389,23 @@ static void read_cb(uv_stream_t* handle, int ipc_send_recv_helper(void) { int r; - memset(&ctx, 0, sizeof(ctx)); - - r = uv_pipe_init(uv_default_loop(), &ctx.channel, 1); + r = run_ipc_send_recv_helper(uv_default_loop(), 0); ASSERT(r == 0); - uv_pipe_open(&ctx.channel, 0); - ASSERT(1 == uv_is_readable((uv_stream_t*)&ctx.channel)); - ASSERT(1 == uv_is_writable((uv_stream_t*)&ctx.channel)); - ASSERT(0 == uv_is_closing((uv_handle_t*)&ctx.channel)); + MAKE_VALGRIND_HAPPY(); + return 0; +} - r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, read_cb); +void ipc_send_recv_helper_threadproc(void* arg) { + int r; + uv_loop_t loop; + + r = uv_loop_init(&loop); ASSERT(r == 0); - r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + r = run_ipc_send_recv_helper(&loop, 1); ASSERT(r == 0); - MAKE_VALGRIND_HAPPY(); - return 0; + r = uv_loop_close(&loop); + ASSERT(r == 0); } diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 8ee74391afaeb7..858a20af49c291 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -50,8 +50,10 @@ TEST_DECLARE (ipc_listen_before_write) TEST_DECLARE (ipc_listen_after_write) #ifndef _WIN32 TEST_DECLARE (ipc_send_recv_pipe) +TEST_DECLARE (ipc_send_recv_pipe_inprocess) #endif TEST_DECLARE (ipc_send_recv_tcp) +TEST_DECLARE (ipc_send_recv_tcp_inprocess) TEST_DECLARE (ipc_tcp_connection) TEST_DECLARE (tcp_ping_pong) TEST_DECLARE (tcp_ping_pong_v6) @@ -252,6 +254,7 @@ TEST_DECLARE (fs_unlink_readonly) TEST_DECLARE (fs_chown) TEST_DECLARE (fs_link) TEST_DECLARE (fs_readlink) +TEST_DECLARE (fs_realpath) TEST_DECLARE (fs_symlink) TEST_DECLARE (fs_symlink_dir) TEST_DECLARE (fs_utime) @@ -334,6 +337,7 @@ HELPER_DECLARE (tcp6_echo_server) HELPER_DECLARE (udp4_echo_server) HELPER_DECLARE (pipe_echo_server) +TEST_DECLARE (queue_foreach_delete) TASK_LIST_START TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000) @@ -380,8 +384,10 @@ TASK_LIST_START TEST_ENTRY (ipc_listen_after_write) #ifndef _WIN32 TEST_ENTRY (ipc_send_recv_pipe) + TEST_ENTRY (ipc_send_recv_pipe_inprocess) #endif TEST_ENTRY (ipc_send_recv_tcp) + TEST_ENTRY (ipc_send_recv_tcp_inprocess) TEST_ENTRY (ipc_tcp_connection) TEST_ENTRY (tcp_ping_pong) @@ -671,6 +677,7 @@ TASK_LIST_START TEST_ENTRY (fs_utime) TEST_ENTRY (fs_futime) TEST_ENTRY (fs_readlink) + TEST_ENTRY (fs_realpath) TEST_ENTRY (fs_symlink) TEST_ENTRY (fs_symlink_dir) TEST_ENTRY (fs_stat_missing_path) @@ -714,6 +721,9 @@ TASK_LIST_START TEST_ENTRY (dlerror) TEST_ENTRY (ip4_addr) TEST_ENTRY (ip6_addr_link_local) + + TEST_ENTRY (queue_foreach_delete) + #if 0 /* These are for testing the test runner. */ TEST_ENTRY (fail_always) diff --git a/deps/uv/test/test-mutexes.c b/deps/uv/test/test-mutexes.c index 4aeac73b4c1571..af5e4e88a22f30 100644 --- a/deps/uv/test/test-mutexes.c +++ b/deps/uv/test/test-mutexes.c @@ -25,6 +25,10 @@ #include #include +static uv_cond_t condvar; +static uv_mutex_t mutex; +static uv_rwlock_t rwlock; +static int step; /* The mutex and rwlock tests are really poor. * They're very basic sanity checks and nothing more. @@ -63,60 +67,96 @@ TEST_IMPL(thread_rwlock) { } -TEST_IMPL(thread_rwlock_trylock) { - uv_rwlock_t rwlock; - int r; - - r = uv_rwlock_init(&rwlock); - ASSERT(r == 0); - - /* No locks held. */ +/* Call when holding |mutex|. */ +static void synchronize_nowait(void) { + step += 1; + uv_cond_signal(&condvar); +} - r = uv_rwlock_trywrlock(&rwlock); - ASSERT(r == 0); - /* Write lock held. */ +/* Call when holding |mutex|. */ +static void synchronize(void) { + int current; - r = uv_rwlock_tryrdlock(&rwlock); - ASSERT(r == UV_EBUSY); - r = uv_rwlock_trywrlock(&rwlock); - ASSERT(r == UV_EBUSY); + synchronize_nowait(); + /* Wait for the other thread. Guard against spurious wakeups. */ + for (current = step; current == step; uv_cond_wait(&condvar, &mutex)); + ASSERT(step == current + 1); +} - uv_rwlock_wrunlock(&rwlock); - /* No locks held. */ +static void thread_rwlock_trylock_peer(void* unused) { + (void) &unused; - r = uv_rwlock_tryrdlock(&rwlock); - ASSERT(r == 0); + uv_mutex_lock(&mutex); - /* One read lock held. */ + /* Write lock held by other thread. */ + ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock)); + ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); + synchronize(); - r = uv_rwlock_tryrdlock(&rwlock); - ASSERT(r == 0); + /* Read lock held by other thread. */ + ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); + uv_rwlock_rdunlock(&rwlock); + ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); + synchronize(); - /* Two read locks held. */ + /* Acquire write lock. */ + ASSERT(0 == uv_rwlock_trywrlock(&rwlock)); + synchronize(); - r = uv_rwlock_trywrlock(&rwlock); - ASSERT(r == UV_EBUSY); + /* Release write lock and acquire read lock. */ + uv_rwlock_wrunlock(&rwlock); + ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); + synchronize(); uv_rwlock_rdunlock(&rwlock); + synchronize_nowait(); /* Signal main thread we're going away. */ + uv_mutex_unlock(&mutex); +} - /* One read lock held. */ - uv_rwlock_rdunlock(&rwlock); +TEST_IMPL(thread_rwlock_trylock) { + uv_thread_t thread; - /* No read locks held. */ + ASSERT(0 == uv_cond_init(&condvar)); + ASSERT(0 == uv_mutex_init(&mutex)); + ASSERT(0 == uv_rwlock_init(&rwlock)); - r = uv_rwlock_trywrlock(&rwlock); - ASSERT(r == 0); + uv_mutex_lock(&mutex); + ASSERT(0 == uv_thread_create(&thread, thread_rwlock_trylock_peer, NULL)); - /* Write lock held. */ + /* Hold write lock. */ + ASSERT(0 == uv_rwlock_trywrlock(&rwlock)); + synchronize(); /* Releases the mutex to the other thread. */ + /* Release write lock and acquire read lock. Pthreads doesn't support + * the notion of upgrading or downgrading rwlocks, so neither do we. + */ uv_rwlock_wrunlock(&rwlock); + ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); + synchronize(); + + /* Release read lock. */ + uv_rwlock_rdunlock(&rwlock); + synchronize(); - /* No locks held. */ + /* Write lock held by other thread. */ + ASSERT(UV_EBUSY == uv_rwlock_tryrdlock(&rwlock)); + ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); + synchronize(); + /* Read lock held by other thread. */ + ASSERT(0 == uv_rwlock_tryrdlock(&rwlock)); + uv_rwlock_rdunlock(&rwlock); + ASSERT(UV_EBUSY == uv_rwlock_trywrlock(&rwlock)); + synchronize(); + + ASSERT(0 == uv_thread_join(&thread)); uv_rwlock_destroy(&rwlock); + uv_mutex_unlock(&mutex); + uv_mutex_destroy(&mutex); + uv_cond_destroy(&condvar); return 0; } diff --git a/deps/uv/test/test-process-title.c b/deps/uv/test/test-process-title.c index 29be20749bea9d..42ade44160416f 100644 --- a/deps/uv/test/test-process-title.c +++ b/deps/uv/test/test-process-title.c @@ -42,7 +42,7 @@ static void set_title(const char* title) { TEST_IMPL(process_title) { -#if defined(__sun) +#if defined(__sun) || defined(_AIX) RETURN_SKIP("uv_(get|set)_process_title is not implemented."); #else /* Check for format string vulnerabilities. */ diff --git a/deps/uv/test/test-queue-foreach-delete.c b/deps/uv/test/test-queue-foreach-delete.c new file mode 100644 index 00000000000000..45da225381f51f --- /dev/null +++ b/deps/uv/test/test-queue-foreach-delete.c @@ -0,0 +1,200 @@ +/* Copyright The libuv project and 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 + + +/* + * The idea behind the test is as follows. + * Certain handle types are stored in a queue internally. + * Extra care should be taken for removal of a handle from the queue while iterating over the queue. + * (i.e., QUEUE_REMOVE() called within QUEUE_FOREACH()) + * This usually happens when someone closes or stops a handle from within its callback. + * So we need to check that we haven't screwed the queue on close/stop. + * To do so we do the following (for each handle type): + * 1. Create and start 3 handles (#0, #1, and #2). + * + * The queue after the start() calls: + * ..=> [queue head] <=> [handle] <=> [handle #1] <=> [handle] <=.. + * + * 2. Trigger handles to fire (for uv_idle_t, uv_prepare_t, and uv_check_t there is nothing to do). + * + * 3. In the callback for the first-executed handle (#0 or #2 depending on handle type) + * stop the handle and the next one (#1). + * (for uv_idle_t, uv_prepare_t, and uv_check_t callbacks are executed in the reverse order as they are start()'ed, + * so callback for handle #2 will be called first) + * + * The queue after the stop() calls: + * correct foreach "next" | + * \/ + * ..=> [queue head] <==============================> [handle] <=.. + * [ ] <- [handle] <=> [handle #1] -> [ ] + * /\ + * wrong foreach "next" | + * + * 4. The callback for handle #1 shouldn't be called because the handle #1 is stopped in the previous step. + * However, if QUEUE_REMOVE() is not handled properly within QUEUE_FOREACH(), the callback _will_ be called. + */ + +static const unsigned first_handle_number_idle = 2; +static const unsigned first_handle_number_prepare = 2; +static const unsigned first_handle_number_check = 2; +#ifdef __linux__ +static const unsigned first_handle_number_fs_event = 0; +#endif + + +#define DEFINE_GLOBALS_AND_CBS(name) \ + static uv_##name##_t (name)[3]; \ + static unsigned name##_cb_calls[3]; \ + \ + static void name##2_cb(uv_##name##_t* handle) { \ + ASSERT(handle == &(name)[2]); \ + if (first_handle_number_##name == 2) { \ + uv_close((uv_handle_t*)&(name)[2], NULL); \ + uv_close((uv_handle_t*)&(name)[1], NULL); \ + } \ + name##_cb_calls[2]++; \ + } \ + \ + static void name##1_cb(uv_##name##_t* handle) { \ + ASSERT(handle == &(name)[1]); \ + ASSERT(0 && "Shouldn't be called" && (&name[0])); \ + } \ + \ + static void name##0_cb(uv_##name##_t* handle) { \ + ASSERT(handle == &(name)[0]); \ + if (first_handle_number_##name == 0) { \ + uv_close((uv_handle_t*)&(name)[0], NULL); \ + uv_close((uv_handle_t*)&(name)[1], NULL); \ + } \ + name##_cb_calls[0]++; \ + } \ + \ + static const uv_##name##_cb name##_cbs[] = { \ + (uv_##name##_cb)name##0_cb, \ + (uv_##name##_cb)name##1_cb, \ + (uv_##name##_cb)name##2_cb, \ + }; + +#define INIT_AND_START(name, loop) \ + do { \ + size_t i; \ + for (i = 0; i < ARRAY_SIZE(name); i++) { \ + int r; \ + r = uv_##name##_init((loop), &(name)[i]); \ + ASSERT(r == 0); \ + \ + r = uv_##name##_start(&(name)[i], name##_cbs[i]); \ + ASSERT(r == 0); \ + } \ + } while (0) + +#define END_ASSERTS(name) \ + do { \ + ASSERT(name##_cb_calls[0] == 1); \ + ASSERT(name##_cb_calls[1] == 0); \ + ASSERT(name##_cb_calls[2] == 1); \ + } while (0) + +DEFINE_GLOBALS_AND_CBS(idle) +DEFINE_GLOBALS_AND_CBS(prepare) +DEFINE_GLOBALS_AND_CBS(check) + +#ifdef __linux__ +DEFINE_GLOBALS_AND_CBS(fs_event) + +static const char watched_dir[] = "."; +static uv_timer_t timer; +static unsigned helper_timer_cb_calls; + + +static void init_and_start_fs_events(uv_loop_t* loop) { + size_t i; + for (i = 0; i < ARRAY_SIZE(fs_event); i++) { + int r; + r = uv_fs_event_init(loop, &fs_event[i]); + ASSERT(r == 0); + + r = uv_fs_event_start(&fs_event[i], + (uv_fs_event_cb)fs_event_cbs[i], + watched_dir, + 0); + ASSERT(r == 0); + } +} + +static void helper_timer_cb(uv_timer_t* thandle) { + int r; + uv_fs_t fs_req; + + /* fire all fs_events */ + r = uv_fs_utime(thandle->loop, &fs_req, watched_dir, 0, 0, NULL); + ASSERT(r == 0); + ASSERT(fs_req.result == 0); + ASSERT(fs_req.fs_type == UV_FS_UTIME); + ASSERT(strcmp(fs_req.path, watched_dir) == 0); + uv_fs_req_cleanup(&fs_req); + + helper_timer_cb_calls++; +} +#endif + + +TEST_IMPL(queue_foreach_delete) { + uv_loop_t* loop; + int r; + + loop = uv_default_loop(); + + INIT_AND_START(idle, loop); + INIT_AND_START(prepare, loop); + INIT_AND_START(check, loop); + +#ifdef __linux__ + init_and_start_fs_events(loop); + + /* helper timer to trigger async and fs_event callbacks */ + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + + r = uv_timer_start(&timer, helper_timer_cb, 0, 0); + ASSERT(r == 0); +#endif + + r = uv_run(loop, UV_RUN_NOWAIT); + ASSERT(r == 1); + + END_ASSERTS(idle); + END_ASSERTS(prepare); + END_ASSERTS(check); + +#ifdef __linux__ + ASSERT(helper_timer_cb_calls == 1); +#endif + + MAKE_VALGRIND_HAPPY(); + + return 0; +} diff --git a/deps/uv/test/test-spawn.c b/deps/uv/test/test-spawn.c index e71f0f7d53d344..eba54ae7054976 100644 --- a/deps/uv/test/test-spawn.c +++ b/deps/uv/test/test-spawn.c @@ -960,11 +960,11 @@ TEST_IMPL(spawn_detect_pipe_name_collisions_on_windows) { options.stdio_count = 2; /* Create a pipe that'll cause a collision. */ - _snprintf(name, - sizeof(name), - "\\\\.\\pipe\\uv\\%p-%d", - &out, - GetCurrentProcessId()); + snprintf(name, + sizeof(name), + "\\\\.\\pipe\\uv\\%p-%d", + &out, + GetCurrentProcessId()); pipe_handle = CreateNamedPipeA(name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, diff --git a/deps/uv/test/test-tcp-try-write.c b/deps/uv/test/test-tcp-try-write.c index 8a60136b64e9aa..97a1d6e3d5794f 100644 --- a/deps/uv/test/test-tcp-try-write.c +++ b/deps/uv/test/test-tcp-try-write.c @@ -58,6 +58,11 @@ static void connect_cb(uv_connect_t* req, int status) { break; } } while (1); + + do { + buf = uv_buf_init("", 0); + r = uv_try_write((uv_stream_t*) &client, &buf, 1); + } while (r != 0); uv_close((uv_handle_t*) &client, close_cb); } diff --git a/deps/uv/test/test-tcp-write-fail.c b/deps/uv/test/test-tcp-write-fail.c index 2840d8161032be..5256a9f4a790aa 100644 --- a/deps/uv/test/test-tcp-write-fail.c +++ b/deps/uv/test/test-tcp-write-fail.c @@ -43,7 +43,7 @@ static void close_socket(uv_tcp_t* sock) { r = uv_fileno((uv_handle_t*)sock, &fd); ASSERT(r == 0); #ifdef _WIN32 - r = closesocket(fd); + r = closesocket((uv_os_sock_t)fd); #else r = close(fd); #endif diff --git a/deps/uv/test/test-threadpool-cancel.c b/deps/uv/test/test-threadpool-cancel.c index cb456224516823..784c1739f6d47e 100644 --- a/deps/uv/test/test-threadpool-cancel.c +++ b/deps/uv/test/test-threadpool-cancel.c @@ -276,7 +276,7 @@ TEST_IMPL(threadpool_cancel_work) { TEST_IMPL(threadpool_cancel_fs) { struct cancel_info ci; - uv_fs_t reqs[25]; + uv_fs_t reqs[26]; uv_loop_t* loop; unsigned n; uv_buf_t iov; @@ -305,6 +305,7 @@ TEST_IMPL(threadpool_cancel_fs) { ASSERT(0 == uv_fs_read(loop, reqs + n++, 0, &iov, 1, 0, fs_cb)); ASSERT(0 == uv_fs_scandir(loop, reqs + n++, "/", 0, fs_cb)); ASSERT(0 == uv_fs_readlink(loop, reqs + n++, "/", fs_cb)); + ASSERT(0 == uv_fs_realpath(loop, reqs + n++, "/", fs_cb)); ASSERT(0 == uv_fs_rename(loop, reqs + n++, "/", "/", fs_cb)); ASSERT(0 == uv_fs_mkdir(loop, reqs + n++, "/", 0, fs_cb)); ASSERT(0 == uv_fs_sendfile(loop, reqs + n++, 0, 0, 0, 0, fs_cb)); diff --git a/deps/uv/test/test-tty.c b/deps/uv/test/test-tty.c index 81e612c1d6ae1c..b844959d526340 100644 --- a/deps/uv/test/test-tty.c +++ b/deps/uv/test/test-tty.c @@ -153,11 +153,14 @@ TEST_IMPL(tty_file) { ASSERT(0 == close(fd)); } +/* Bug on AIX where '/dev/random' returns 1 from isatty() */ +#ifndef _AIX fd = open("/dev/random", O_RDONLY); if (fd != -1) { ASSERT(UV_EINVAL == uv_tty_init(&loop, &tty, fd, 1)); ASSERT(0 == close(fd)); } +#endif /* _AIX */ fd = open("/dev/zero", O_RDONLY); if (fd != -1) { diff --git a/deps/uv/test/test-udp-ipv6.c b/deps/uv/test/test-udp-ipv6.c index 1d5720ce73162a..1b0db78b8efcea 100644 --- a/deps/uv/test/test-udp-ipv6.c +++ b/deps/uv/test/test-udp-ipv6.c @@ -26,6 +26,10 @@ #include #include +#ifdef __FreeBSD__ +#include +#endif + #define CHECK_HANDLE(handle) \ ASSERT((uv_udp_t*)(handle) == &server \ || (uv_udp_t*)(handle) == &client \ @@ -43,6 +47,18 @@ static int send_cb_called; static int recv_cb_called; static int close_cb_called; +#ifdef __FreeBSD__ +static int can_ipv6_ipv4_dual() { + int v6only; + size_t size = sizeof(int); + + if (sysctlbyname("net.inet6.ip6.v6only", &v6only, &size, NULL, 0)) + return 0; + + return v6only != 1; +} +#endif + static void alloc_cb(uv_handle_t* handle, size_t suggested_size, @@ -150,6 +166,11 @@ TEST_IMPL(udp_dual_stack) { if (!can_ipv6()) RETURN_SKIP("IPv6 not supported"); +#ifdef __FreeBSD__ + if (!can_ipv6_ipv4_dual()) + RETURN_SKIP("IPv6-IPv4 dual stack not supported"); +#endif + do_test(ipv6_recv_ok, 0); ASSERT(recv_cb_called == 1); diff --git a/deps/uv/test/test-udp-multicast-join6.c b/deps/uv/test/test-udp-multicast-join6.c index 873cb6d811d749..f635bdb9e14ee2 100644 --- a/deps/uv/test/test-udp-multicast-join6.c +++ b/deps/uv/test/test-udp-multicast-join6.c @@ -119,7 +119,7 @@ TEST_IMPL(udp_multicast_join6) { ASSERT(r == 0); /* join the multicast channel */ -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(_AIX) r = uv_udp_set_membership(&client, "ff02::1", "::1%lo0", UV_JOIN_GROUP); #else r = uv_udp_set_membership(&client, "ff02::1", NULL, UV_JOIN_GROUP); diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 8049faa7a66929..635a234ea6eee8 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -104,6 +104,13 @@ 'src/win/winsock.c', 'src/win/winsock.h', ], + 'conditions': [ + ['MSVS_VERSION < "2015"', { + 'sources': [ + 'src/win/snprintf.c' + ] + }] + ], 'link_settings': { 'libraries': [ '-ladvapi32', @@ -340,6 +347,7 @@ 'test/test-poll-close-doesnt-corrupt-stack.c', 'test/test-poll-closesocket.c', 'test/test-process-title.c', + 'test/test-queue-foreach-delete.c', 'test/test-ref.c', 'test/test-run-nowait.c', 'test/test-run-once.c',