From: Serhiy Storchaka Date: Tue, 20 Aug 2013 17:38:21 +0000 (+0300) Subject: Issue #8865: Concurrent invocation of select.poll.poll() now raises a X-Git-Tag: v2.7.6rc1~215 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c360389453d50ff3fdebea052a0f436be41cc8c4;p=thirdparty%2FPython%2Fcpython.git Issue #8865: Concurrent invocation of select.poll.poll() now raises a RuntimeError exception. Patch by Christian Schubert. --- diff --git a/Lib/test/test_poll.py b/Lib/test/test_poll.py index 55294f8c2293..219fa0e4647b 100644 --- a/Lib/test/test_poll.py +++ b/Lib/test/test_poll.py @@ -1,8 +1,16 @@ # Test case for the os.poll() function -import os, select, random, unittest +import os +import random +import select import _testcapi -from test.test_support import TESTFN, run_unittest +try: + import threading +except ImportError: + threading = None +import time +import unittest +from test.test_support import TESTFN, run_unittest, reap_threads try: select.poll @@ -160,6 +168,36 @@ class PollTests(unittest.TestCase): self.assertRaises(OverflowError, pollster.poll, _testcapi.INT_MAX + 1) self.assertRaises(OverflowError, pollster.poll, _testcapi.UINT_MAX + 1) + @unittest.skipUnless(threading, 'Threading required for this test.') + @reap_threads + def test_threaded_poll(self): + r, w = os.pipe() + self.addCleanup(os.close, r) + self.addCleanup(os.close, w) + rfds = [] + for i in range(10): + fd = os.dup(r) + self.addCleanup(os.close, fd) + rfds.append(fd) + pollster = select.poll() + for fd in rfds: + pollster.register(fd, select.POLLIN) + + t = threading.Thread(target=pollster.poll) + t.start() + try: + time.sleep(0.5) + # trigger ufds array reallocation + for fd in rfds: + pollster.unregister(fd) + pollster.register(w, select.POLLOUT) + self.assertRaises(RuntimeError, pollster.poll) + finally: + # and make the call to poll() from the thread return + os.write(w, b'spam') + t.join() + + def test_main(): run_unittest(PollTests) diff --git a/Misc/ACKS b/Misc/ACKS index 8aba36e30050..c6c2e2f2396e 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -912,6 +912,7 @@ Peter Schneider-Kamp Arvin Schnell Scott Schram Chad J. Schroeder +Christian Schubert Sam Schulenburg Stefan Schwarzer Dietmar Schwertberger diff --git a/Misc/NEWS b/Misc/NEWS index 9ee4cfe26700..4c39da3748fc 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -32,6 +32,9 @@ Core and Builtins Library ------- +- Issue #8865: Concurrent invocation of select.poll.poll() now raises a + RuntimeError exception. Patch by Christian Schubert. + - Issue #13461: Fix a crash in the TextIOWrapper.tell method on 64-bit platforms. Patch by Yogesh Chaudhari. diff --git a/Modules/selectmodule.c b/Modules/selectmodule.c index 4cbf885b18fe..00d5f6c058c5 100644 --- a/Modules/selectmodule.c +++ b/Modules/selectmodule.c @@ -318,6 +318,7 @@ typedef struct { int ufd_uptodate; int ufd_len; struct pollfd *ufds; + int poll_running; } pollObject; static PyTypeObject poll_Type; @@ -513,16 +514,27 @@ poll_poll(pollObject *self, PyObject *args) return NULL; } + /* Avoid concurrent poll() invocation, issue 8865 */ + if (self->poll_running) { + PyErr_SetString(PyExc_RuntimeError, + "concurrent poll() invocation"); + return NULL; + } + /* Ensure the ufd array is up to date */ if (!self->ufd_uptodate) if (update_ufd_array(self) == 0) return NULL; + self->poll_running = 1; + /* call poll() */ Py_BEGIN_ALLOW_THREADS poll_result = poll(self->ufds, self->ufd_len, timeout); Py_END_ALLOW_THREADS + self->poll_running = 0; + if (poll_result < 0) { PyErr_SetFromErrno(SelectError); return NULL; @@ -599,6 +611,7 @@ newPollObject(void) array pointed to by ufds matches the contents of the dictionary. */ self->ufd_uptodate = 0; self->ufds = NULL; + self->poll_running = 0; self->dict = PyDict_New(); if (self->dict == NULL) { Py_DECREF(self);