Commit c3603894 authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #8865: Concurrent invocation of select.poll.poll() now raises a

RuntimeError exception.  Patch by Christian Schubert.
parent a9885e93
# Test case for the os.poll() function # Test case for the os.poll() function
import os, select, random, unittest import os
import random
import select
import _testcapi 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: try:
select.poll select.poll
...@@ -160,6 +168,36 @@ class PollTests(unittest.TestCase): ...@@ -160,6 +168,36 @@ class PollTests(unittest.TestCase):
self.assertRaises(OverflowError, pollster.poll, _testcapi.INT_MAX + 1) self.assertRaises(OverflowError, pollster.poll, _testcapi.INT_MAX + 1)
self.assertRaises(OverflowError, pollster.poll, _testcapi.UINT_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(): def test_main():
run_unittest(PollTests) run_unittest(PollTests)
......
...@@ -912,6 +912,7 @@ Peter Schneider-Kamp ...@@ -912,6 +912,7 @@ Peter Schneider-Kamp
Arvin Schnell Arvin Schnell
Scott Schram Scott Schram
Chad J. Schroeder Chad J. Schroeder
Christian Schubert
Sam Schulenburg Sam Schulenburg
Stefan Schwarzer Stefan Schwarzer
Dietmar Schwertberger Dietmar Schwertberger
......
...@@ -32,6 +32,9 @@ Core and Builtins ...@@ -32,6 +32,9 @@ Core and Builtins
Library 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 - Issue #13461: Fix a crash in the TextIOWrapper.tell method on 64-bit
platforms. Patch by Yogesh Chaudhari. platforms. Patch by Yogesh Chaudhari.
......
...@@ -318,6 +318,7 @@ typedef struct { ...@@ -318,6 +318,7 @@ typedef struct {
int ufd_uptodate; int ufd_uptodate;
int ufd_len; int ufd_len;
struct pollfd *ufds; struct pollfd *ufds;
int poll_running;
} pollObject; } pollObject;
static PyTypeObject poll_Type; static PyTypeObject poll_Type;
...@@ -513,16 +514,27 @@ poll_poll(pollObject *self, PyObject *args) ...@@ -513,16 +514,27 @@ poll_poll(pollObject *self, PyObject *args)
return NULL; 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 */ /* Ensure the ufd array is up to date */
if (!self->ufd_uptodate) if (!self->ufd_uptodate)
if (update_ufd_array(self) == 0) if (update_ufd_array(self) == 0)
return NULL; return NULL;
self->poll_running = 1;
/* call poll() */ /* call poll() */
Py_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS
poll_result = poll(self->ufds, self->ufd_len, timeout); poll_result = poll(self->ufds, self->ufd_len, timeout);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
self->poll_running = 0;
if (poll_result < 0) { if (poll_result < 0) {
PyErr_SetFromErrno(SelectError); PyErr_SetFromErrno(SelectError);
return NULL; return NULL;
...@@ -599,6 +611,7 @@ newPollObject(void) ...@@ -599,6 +611,7 @@ newPollObject(void)
array pointed to by ufds matches the contents of the dictionary. */ array pointed to by ufds matches the contents of the dictionary. */
self->ufd_uptodate = 0; self->ufd_uptodate = 0;
self->ufds = NULL; self->ufds = NULL;
self->poll_running = 0;
self->dict = PyDict_New(); self->dict = PyDict_New();
if (self->dict == NULL) { if (self->dict == NULL) {
Py_DECREF(self); Py_DECREF(self);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment