diff -r c080ef5989f7 Modules/socketmodule.c --- a/Modules/socketmodule.c Fri Jan 29 19:09:41 2016 -0600 +++ b/Modules/socketmodule.c Tue Feb 09 21:37:13 2016 -0500 @@ -183,15 +183,66 @@ #ifdef HAVE_SYS_PARAM_H #include #endif + +#if defined(WITH_THREAD) && defined(__APPLE__) +#include + +#define USE_GETADDRINFO_LOCK_APPLE + +static int needs_getaddrinfo_lock = -1; + +/* Determine if we must lock around getaddrinfo on Mac OS X. + + 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 for details. */ +static int +set_needs_getaddrinfo_lock(void) +{ + struct utsname names; + int ret, major, minor, patch; + + /* "sysctlbyname" wasn't found to work on Mac OS 10.4, but uname should */ + ret = uname(&names); + if (ret < 0) { + PyErr_Format(PyExc_ImportError, "uname failed: error code %d", ret); + return -1; + } + + /* parse release string: "x.y.z" */ + ret = sscanf(names.release, "%d.%d.%d", &major, &minor, &patch); + if (ret != 3) { + PyErr_Format(PyExc_ImportError, + "Cannot parse uname: \"%s\"", names.release); + return -1; + } + + needs_getaddrinfo_lock = ((major * 100 + minor) < 105); /* before 10.5? */ + + return 0; +} + +#else /* On systems on which getaddrinfo() is believed to not be thread-safe, (this includes the getaddrinfo emulation) protect access with a lock. */ -#if defined(WITH_THREAD) && (defined(__APPLE__) || \ +#if defined(WITH_THREAD) && ( (defined(__FreeBSD__) && __FreeBSD_version+0 < 503000) || \ defined(__OpenBSD__) || defined(__NetBSD__) || \ !defined(HAVE_GETADDRINFO)) #define USE_GETADDRINFO_LOCK #endif - +#endif + +#ifdef USE_GETADDRINFO_LOCK_APPLE +#define ACQUIRE_GETADDRINFO_LOCK \ + if (needs_getaddrinfo_lock) { PyThread_acquire_lock(netdb_lock, 1); } +#define RELEASE_GETADDRINFO_LOCK \ + if (needs_getaddrinfo_lock) { PyThread_release_lock(netdb_lock); } +#else #ifdef USE_GETADDRINFO_LOCK #define ACQUIRE_GETADDRINFO_LOCK PyThread_acquire_lock(netdb_lock, 1); #define RELEASE_GETADDRINFO_LOCK PyThread_release_lock(netdb_lock); @@ -199,6 +250,7 @@ #define ACQUIRE_GETADDRINFO_LOCK #define RELEASE_GETADDRINFO_LOCK #endif +#endif #if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK) # include "pythread.h" @@ -6091,6 +6143,12 @@ if (!os_init()) return NULL; +#if defined(WITH_THREAD) && defined(__APPLE__) + if (set_needs_getaddrinfo_lock() != 0) { + return NULL; + } +#endif + #ifdef MS_WINDOWS if (support_wsa_no_inherit == -1) { #if defined(_MSC_VER) && _MSC_VER >= 1800