Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b1973c2

Browse files
Issue #8865: Concurrent invocation of select.poll.poll() now raises a
RuntimeError exception. Patch by Christian Schubert.
1 parent ec67d18 commit b1973c2

4 files changed

Lines changed: 57 additions & 2 deletions

File tree

Lib/test/test_poll.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
# Test case for the os.poll() function
22

3-
import os, select, random, unittest
3+
import os
4+
import random
5+
import select
46
import _testcapi
5-
from test.support import TESTFN, run_unittest
7+
try:
8+
import threading
9+
except ImportError:
10+
threading = None
11+
import time
12+
import unittest
13+
from test.support import TESTFN, run_unittest, reap_threads
614

715
try:
816
select.poll
@@ -160,6 +168,36 @@ def test_poll3(self):
160168
self.assertRaises(OverflowError, pollster.poll, _testcapi.INT_MAX + 1)
161169
self.assertRaises(OverflowError, pollster.poll, _testcapi.UINT_MAX + 1)
162170

171+
@unittest.skipUnless(threading, 'Threading required for this test.')
172+
@reap_threads
173+
def test_threaded_poll(self):
174+
r, w = os.pipe()
175+
self.addCleanup(os.close, r)
176+
self.addCleanup(os.close, w)
177+
rfds = []
178+
for i in range(10):
179+
fd = os.dup(r)
180+
self.addCleanup(os.close, fd)
181+
rfds.append(fd)
182+
pollster = select.poll()
183+
for fd in rfds:
184+
pollster.register(fd, select.POLLIN)
185+
186+
t = threading.Thread(target=pollster.poll)
187+
t.start()
188+
try:
189+
time.sleep(0.5)
190+
# trigger ufds array reallocation
191+
for fd in rfds:
192+
pollster.unregister(fd)
193+
pollster.register(w, select.POLLOUT)
194+
self.assertRaises(RuntimeError, pollster.poll)
195+
finally:
196+
# and make the call to poll() from the thread return
197+
os.write(w, b'spam')
198+
t.join()
199+
200+
163201
def test_main():
164202
run_unittest(PollTests)
165203

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,6 +1097,7 @@ Arvin Schnell
10971097
Scott Schram
10981098
Robin Schreiber
10991099
Chad J. Schroeder
1100+
Christian Schubert
11001101
Sam Schulenburg
11011102
Stefan Schwarzer
11021103
Dietmar Schwertberger

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ Core and Builtins
6666
Library
6767
-------
6868

69+
- Issue #8865: Concurrent invocation of select.poll.poll() now raises a
70+
RuntimeError exception. Patch by Christian Schubert.
71+
6972
- Issue #13461: Fix a crash in the TextIOWrapper.tell method on 64-bit
7073
platforms. Patch by Yogesh Chaudhari.
7174

Modules/selectmodule.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ typedef struct {
332332
int ufd_uptodate;
333333
int ufd_len;
334334
struct pollfd *ufds;
335+
int poll_running;
335336
} pollObject;
336337

337338
static PyTypeObject poll_Type;
@@ -528,16 +529,27 @@ poll_poll(pollObject *self, PyObject *args)
528529
return NULL;
529530
}
530531

532+
/* Avoid concurrent poll() invocation, issue 8865 */
533+
if (self->poll_running) {
534+
PyErr_SetString(PyExc_RuntimeError,
535+
"concurrent poll() invocation");
536+
return NULL;
537+
}
538+
531539
/* Ensure the ufd array is up to date */
532540
if (!self->ufd_uptodate)
533541
if (update_ufd_array(self) == 0)
534542
return NULL;
535543

544+
self->poll_running = 1;
545+
536546
/* call poll() */
537547
Py_BEGIN_ALLOW_THREADS
538548
poll_result = poll(self->ufds, self->ufd_len, timeout);
539549
Py_END_ALLOW_THREADS
540550

551+
self->poll_running = 0;
552+
541553
if (poll_result < 0) {
542554
PyErr_SetFromErrno(PyExc_OSError);
543555
return NULL;
@@ -614,6 +626,7 @@ newPollObject(void)
614626
array pointed to by ufds matches the contents of the dictionary. */
615627
self->ufd_uptodate = 0;
616628
self->ufds = NULL;
629+
self->poll_running = 0;
617630
self->dict = PyDict_New();
618631
if (self->dict == NULL) {
619632
Py_DECREF(self);

0 commit comments

Comments
 (0)