From 2138dd2f08853b376c4154edd3b1a50262746692 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sat, 4 May 2019 13:46:14 +0200 Subject: [PATCH] linux: fix thread cancellation fd leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Same as the previous commit but this time for Linux. Specifically, the glibc close() wrapper is a cancellation point; the thread is unwound when close() is called when the thread is in the "cancel" state. That's according to spec and therefore arguably less severe than MacOS's "EINTR without actually closing" behavior but we can avoid the file descriptor leak altogether by sidestepping glibc and making the system call directly. Musl libc is unaffected, its close() wrapper doesn't check the cancel state. PR-URL: https://github.com/libuv/libuv/pull/2291 Reviewed-By: Saúl Ibarra Corretgé Reviewed-By: Colin Ihrig --- src/unix/core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/unix/core.c b/src/unix/core.c index d0a4037c..3bada900 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -88,6 +88,10 @@ #include #endif +#if defined(__linux__) +#include +#endif + static int uv__run_pending(uv_loop_t* loop); /* Verify that uv_buf_t is ABI-compatible with struct iovec. */ @@ -513,6 +517,10 @@ skip: /* close() on macos has the "interesting" quirk that it fails with EINTR * without closing the file descriptor when a thread is in the cancel state. * That's why libuv calls close$NOCANCEL() instead. + * + * glibc on linux has a similar issue: close() is a cancellation point and + * will unwind the thread when it's in the cancel state. Work around that + * by making the system call directly. Musl libc is unaffected. */ int uv__close_nocancel(int fd) { #if defined(__APPLE__) @@ -521,6 +529,8 @@ int uv__close_nocancel(int fd) { extern int close$NOCANCEL(int); return close$NOCANCEL(fd); #pragma GCC diagnostic pop +#elif defined(__linux__) + return syscall(SYS_close, fd); #else return close(fd); #endif