diff --git a/Misc/NEWS.d/next/Library/2020-05-18-15-38-25.bpo-25920.PxrLY8.rst b/Misc/NEWS.d/next/Library/2020-05-18-15-38-25.bpo-25920.PxrLY8.rst new file mode 100644 index 00000000000000..cc60e976286c33 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-05-18-15-38-25.bpo-25920.PxrLY8.rst @@ -0,0 +1,7 @@ +On macOS, when building Python for macOS 10.4 and older, which wasn't the case +for python.org macOS installer, :func:`socket.getaddrinfo` no longer uses an +internal lock to prevent race conditions when calling ``getaddrinfo()`` which +is thread-safe since macOS 10.5. Python 3.9 requires macOS 10.6 or newer. The +internal lock caused random hang on fork when another thread was calling +:func:`socket.getaddrinfo`. The lock was also used on FreeBSD older than 5.3, +OpenBSD older than 201311 and NetBSD older than 4. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 92c246ebea76fc..f60a27ebe408c9 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -197,43 +197,6 @@ if_indextoname(index) -- return the corresponding interface name\n\ # define USE_GETHOSTBYNAME_LOCK #endif -/* To use __FreeBSD_version, __OpenBSD__, and __NetBSD_Version__ */ -#ifdef HAVE_SYS_PARAM_H -#include -#endif -/* On systems on which getaddrinfo() is believed to not be thread-safe, - (this includes the getaddrinfo emulation) protect access with a lock. - - getaddrinfo is thread-safe on Mac OS X 10.5 and later. Originally it was - a mix of code including an unsafe implementation from an old BSD's - libresolv. In 10.5 Apple reimplemented it as a safe IPC call to the - mDNSResponder process. 10.5 is the first be UNIX '03 certified, which - includes the requirement that getaddrinfo be thread-safe. See issue #25924. - - It's thread-safe in OpenBSD starting with 5.4, released Nov 2013: - http://www.openbsd.org/plus54.html - - It's thread-safe in NetBSD starting with 4.0, released Dec 2007: - -http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/net/getaddrinfo.c.diff?r1=1.82&r2=1.83 - */ -#if ((defined(__APPLE__) && \ - MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) || \ - (defined(__FreeBSD__) && __FreeBSD_version+0 < 503000) || \ - (defined(__OpenBSD__) && OpenBSD+0 < 201311) || \ - (defined(__NetBSD__) && __NetBSD_Version__+0 < 400000000) || \ - !defined(HAVE_GETADDRINFO)) -#define USE_GETADDRINFO_LOCK -#endif - -#ifdef USE_GETADDRINFO_LOCK -#define ACQUIRE_GETADDRINFO_LOCK PyThread_acquire_lock(netdb_lock, 1); -#define RELEASE_GETADDRINFO_LOCK PyThread_release_lock(netdb_lock); -#else -#define ACQUIRE_GETADDRINFO_LOCK -#define RELEASE_GETADDRINFO_LOCK -#endif - #if defined(__APPLE__) || defined(__CYGWIN__) || defined(__NetBSD__) # include #endif @@ -1061,7 +1024,7 @@ new_sockobject(SOCKET_T fd, int family, int type, int proto) /* Lock to allow python interpreter to continue, but only allow one thread to be in gethostbyname or getaddrinfo */ -#if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK) +#if defined(USE_GETHOSTBYNAME_LOCK) static PyThread_type_lock netdb_lock; #endif @@ -1086,14 +1049,12 @@ setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int hints.ai_socktype = SOCK_DGRAM; /*dummy*/ hints.ai_flags = AI_PASSIVE; Py_BEGIN_ALLOW_THREADS - ACQUIRE_GETADDRINFO_LOCK error = getaddrinfo(NULL, "0", &hints, &res); Py_END_ALLOW_THREADS /* We assume that those thread-unsafe getaddrinfo() versions *are* safe regarding their return value, ie. that a subsequent call to getaddrinfo() does not destroy the outcome of the first call. */ - RELEASE_GETADDRINFO_LOCK if (error) { set_gaierror(error); return -1; @@ -1194,7 +1155,6 @@ setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int memset(&hints, 0, sizeof(hints)); hints.ai_family = af; Py_BEGIN_ALLOW_THREADS - ACQUIRE_GETADDRINFO_LOCK error = getaddrinfo(name, NULL, &hints, &res); #if defined(__digital__) && defined(__unix__) if (error == EAI_NONAME && af == AF_UNSPEC) { @@ -1205,7 +1165,6 @@ setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int } #endif Py_END_ALLOW_THREADS - RELEASE_GETADDRINFO_LOCK /* see comment in setipaddr() */ if (error) { set_gaierror(error); return -1; @@ -6563,10 +6522,8 @@ socket_getaddrinfo(PyObject *self, PyObject *args, PyObject* kwargs) hints.ai_protocol = protocol; hints.ai_flags = flags; Py_BEGIN_ALLOW_THREADS - ACQUIRE_GETADDRINFO_LOCK error = getaddrinfo(hptr, pptr, &hints, &res0); Py_END_ALLOW_THREADS - RELEASE_GETADDRINFO_LOCK /* see comment in setipaddr() */ if (error) { set_gaierror(error); goto err; @@ -6659,10 +6616,8 @@ socket_getnameinfo(PyObject *self, PyObject *args) hints.ai_socktype = SOCK_DGRAM; /* make numeric port happy */ hints.ai_flags = AI_NUMERICHOST; /* don't do any name resolution */ Py_BEGIN_ALLOW_THREADS - ACQUIRE_GETADDRINFO_LOCK error = getaddrinfo(hostp, pbuf, &hints, &res); Py_END_ALLOW_THREADS - RELEASE_GETADDRINFO_LOCK /* see comment in setipaddr() */ if (error) { set_gaierror(error); goto fail; @@ -8422,7 +8377,7 @@ PyInit__socket(void) #endif /* _MSTCPIP_ */ /* Initialize gethostbyname lock */ -#if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK) +#if defined(USE_GETHOSTBYNAME_LOCK) netdb_lock = PyThread_allocate_lock(); #endif