]> granicus.if.org Git - python/commitdiff
bpo-37811: FreeBSD, OSX: fix poll(2) usage in sockets module (GH-15202)
authorArtem Khramov <akhramov@pm.me>
Wed, 14 Aug 2019 21:21:48 +0000 (03:21 +0600)
committerVictor Stinner <vstinner@redhat.com>
Wed, 14 Aug 2019 21:21:48 +0000 (23:21 +0200)
FreeBSD implementation of poll(2) restricts the timeout argument to be
either zero, or positive, or equal to INFTIM (-1).

Unless otherwise overridden, socket timeout defaults to -1. This value
is then converted to milliseconds (-1000) and used as argument to the
poll syscall. poll returns EINVAL (22), and the connection fails.

This bug was discovered during the EINTR handling testing, and the
reproduction code can be found in
https://bugs.python.org/issue23618 (see connect_eintr.py,
attached). On GNU/Linux, the example runs as expected.

This change is trivial:
If the supplied timeout value is negative, truncate it to -1.

Misc/ACKS
Misc/NEWS.d/next/Library/2019-08-14-21-41-07.bpo-37811.d1xYj7.rst [new file with mode: 0644]
Modules/socketmodule.c

index 3b4cf85c75fe55266380c6239f48881ebc012397..52a5d70e5e2d318cc17386e5db2e217983059427 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -837,6 +837,7 @@ Lawrence Kesteloot
 Garvit Khatri
 Vivek Khera
 Dhiru Kholia
+Artem Khramov
 Akshit Khurana
 Sanyam Khurana
 Mads Kiilerich
diff --git a/Misc/NEWS.d/next/Library/2019-08-14-21-41-07.bpo-37811.d1xYj7.rst b/Misc/NEWS.d/next/Library/2019-08-14-21-41-07.bpo-37811.d1xYj7.rst
new file mode 100644 (file)
index 0000000..662e7dc
--- /dev/null
@@ -0,0 +1,4 @@
+Fix ``socket`` module's ``socket.connect(address)`` function being unable to
+establish connection in case of interrupted system call. The problem was
+observed on all OSes which ``poll(2)`` system call can take only
+non-negative integers and -1 as a timeout value.
index f220c26363192891ab1f0b41c0eb29628da9529b..d4f2098e1e6f3d7d4bcb1ebf9fad9021095cf7db 100755 (executable)
@@ -789,6 +789,17 @@ internal_select(PySocketSockObject *s, int writing, _PyTime_t interval,
     ms = _PyTime_AsMilliseconds(interval, _PyTime_ROUND_CEILING);
     assert(ms <= INT_MAX);
 
+    /* On some OSes, typically BSD-based ones, the timeout parameter of the
+       poll() syscall, when negative, must be exactly INFTIM, where defined,
+       or -1. See issue 37811. */
+    if (ms < 0) {
+#ifdef INFTIM
+        ms = INFTIM;
+#else
+        ms = -1;
+#endif
+    }
+
     Py_BEGIN_ALLOW_THREADS;
     n = poll(&pollfd, 1, (int)ms);
     Py_END_ALLOW_THREADS;