From 6cfa927ceb931ad968b5b03e4a2bffb64a8a0604 Mon Sep 17 00:00:00 2001 From: Riccardo Coccioli Date: Tue, 17 Oct 2017 21:45:07 +0200 Subject: [PATCH] bpo-31334: Fix timeout in select.poll.poll() (GH-3277) Always pass -1, or INFTIM where defined, to the poll() system call when a negative timeout is passed to the poll.poll([timeout]) method in the select module. Various OSes throw an error with arbitrary negative values. --- Lib/test/test_poll.py | 2 +- Misc/ACKS | 1 + .../2017-09-04-00-22-31.bpo-31334.9WYRfi.rst | 3 +++ Modules/selectmodule.c | 25 ++++++++++++------- 4 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2017-09-04-00-22-31.bpo-31334.9WYRfi.rst diff --git a/Lib/test/test_poll.py b/Lib/test/test_poll.py index 028dd2d08a..d593495a99 100644 --- a/Lib/test/test_poll.py +++ b/Lib/test/test_poll.py @@ -207,7 +207,7 @@ class PollTests(unittest.TestCase): @unittest.skipUnless(threading, 'Threading required for this test.') @reap_threads def test_poll_blocks_with_negative_ms(self): - for timeout_ms in [None, -1, -1.0, -0.1, -1e-100]: + for timeout_ms in [None, -1000, -1, -1.0, -0.1, -1e-100]: # Create two file descriptors. This will be used to unlock # the blocking call to poll.poll inside the thread r, w = os.pipe() diff --git a/Misc/ACKS b/Misc/ACKS index 38f68aca21..8b9f62eaf7 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -292,6 +292,7 @@ Brad Clements Robbie Clemons Steve Clift Hervé Coatanhay +Riccardo Coccioli Nick Coghlan Josh Cogliati Dave Cole diff --git a/Misc/NEWS.d/next/Library/2017-09-04-00-22-31.bpo-31334.9WYRfi.rst b/Misc/NEWS.d/next/Library/2017-09-04-00-22-31.bpo-31334.9WYRfi.rst new file mode 100644 index 0000000000..1cbfd2531b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-09-04-00-22-31.bpo-31334.9WYRfi.rst @@ -0,0 +1,3 @@ +Fix ``poll.poll([timeout])`` in the ``select`` module for arbitrary negative +timeouts on all OSes where it can only be a non-negative integer or -1. +Patch by Riccardo Coccioli. diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index 530552324b..0f353fbe84 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -525,20 +525,14 @@ poll_poll(pollObject *self, PyObject *args) PyObject *result_list = NULL, *timeout_obj = NULL; int poll_result, i, j; PyObject *value = NULL, *num = NULL; - _PyTime_t timeout, ms, deadline; + _PyTime_t timeout = -1, ms = -1, deadline = 0; int async_err = 0; if (!PyArg_ParseTuple(args, "|O:poll", &timeout_obj)) { return NULL; } - /* Check values for timeout */ - if (timeout_obj == NULL || timeout_obj == Py_None) { - timeout = -1; - ms = -1; - deadline = 0; /* initialize to prevent gcc warning */ - } - else { + if (timeout_obj != NULL && timeout_obj != Py_None) { if (_PyTime_FromMillisecondsObject(&timeout, timeout_obj, _PyTime_ROUND_TIMEOUT) < 0) { if (PyErr_ExceptionMatches(PyExc_TypeError)) { @@ -554,7 +548,20 @@ poll_poll(pollObject *self, PyObject *args) return NULL; } - deadline = _PyTime_GetMonotonicClock() + timeout; + if (timeout >= 0) { + deadline = _PyTime_GetMonotonicClock() + timeout; + } + } + + /* 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 31334. */ + if (ms < 0) { +#ifdef INFTIM + ms = INFTIM; +#else + ms = -1; +#endif } /* Avoid concurrent poll() invocation, issue 8865 */ -- 2.40.0