Skip to content

Commit

Permalink
bpo-37811: FreeBSD, OSX: fix poll(2) usage in sockets module (pythonG…
Browse files Browse the repository at this point in the history
…H-15202)

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.
  • Loading branch information
akhramov authored and vstinner committed Aug 14, 2019
1 parent dcfe111 commit 2814620
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 0 deletions.
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,7 @@ Lawrence Kesteloot
Garvit Khatri
Vivek Khera
Dhiru Kholia
Artem Khramov
Akshit Khurana
Sanyam Khurana
Mads Kiilerich
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
11 changes: 11 additions & 0 deletions Modules/socketmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 2814620

Please sign in to comment.