gh-135410: use a critical section around StringIO.__next__
(#135412)
This commit is contained in:
parent
d447129758
commit
e6c3039cb3
@ -5,6 +5,7 @@ BytesIO -- for bytes
|
|||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from test import support
|
from test import support
|
||||||
|
from test.support import threading_helper
|
||||||
|
|
||||||
import gc
|
import gc
|
||||||
import io
|
import io
|
||||||
@ -12,6 +13,7 @@ import _pyio as pyio
|
|||||||
import pickle
|
import pickle
|
||||||
import sys
|
import sys
|
||||||
import weakref
|
import weakref
|
||||||
|
import threading
|
||||||
|
|
||||||
class IntLike:
|
class IntLike:
|
||||||
def __init__(self, num):
|
def __init__(self, num):
|
||||||
@ -723,6 +725,22 @@ class TextIOTestMixin:
|
|||||||
for newline in (None, "", "\n", "\r", "\r\n"):
|
for newline in (None, "", "\n", "\r", "\r\n"):
|
||||||
self.ioclass(newline=newline)
|
self.ioclass(newline=newline)
|
||||||
|
|
||||||
|
@unittest.skipUnless(support.Py_GIL_DISABLED, "only meaningful under free-threading")
|
||||||
|
@threading_helper.requires_working_threading()
|
||||||
|
def test_concurrent_use(self):
|
||||||
|
memio = self.ioclass("")
|
||||||
|
|
||||||
|
def use():
|
||||||
|
memio.write("x" * 10)
|
||||||
|
memio.readlines()
|
||||||
|
|
||||||
|
threads = [threading.Thread(target=use) for _ in range(8)]
|
||||||
|
with threading_helper.catch_threading_exception() as cm:
|
||||||
|
with threading_helper.start_threads(threads):
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.assertIsNone(cm.exc_value)
|
||||||
|
|
||||||
|
|
||||||
class PyStringIOTest(MemoryTestMixin, MemorySeekTestMixin,
|
class PyStringIOTest(MemoryTestMixin, MemorySeekTestMixin,
|
||||||
TextIOTestMixin, unittest.TestCase):
|
TextIOTestMixin, unittest.TestCase):
|
||||||
@ -890,6 +908,7 @@ class CStringIOTest(PyStringIOTest):
|
|||||||
self.assertRaises(ValueError, memio.__setstate__, ("closed", "", 0, None))
|
self.assertRaises(ValueError, memio.__setstate__, ("closed", "", 0, None))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CStringIOPickleTest(PyStringIOPickleTest):
|
class CStringIOPickleTest(PyStringIOPickleTest):
|
||||||
UnsupportedOperation = io.UnsupportedOperation
|
UnsupportedOperation = io.UnsupportedOperation
|
||||||
|
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
Fix a crash when iterating over :class:`io.StringIO` on the :term:`free
|
||||||
|
threaded <free threading>` build.
|
@ -404,7 +404,7 @@ _io_StringIO_readline_impl(stringio *self, Py_ssize_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
stringio_iternext(PyObject *op)
|
stringio_iternext_lock_held(PyObject *op)
|
||||||
{
|
{
|
||||||
PyObject *line;
|
PyObject *line;
|
||||||
stringio *self = stringio_CAST(op);
|
stringio *self = stringio_CAST(op);
|
||||||
@ -441,6 +441,16 @@ stringio_iternext(PyObject *op)
|
|||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
stringio_iternext(PyObject *op)
|
||||||
|
{
|
||||||
|
PyObject *res;
|
||||||
|
Py_BEGIN_CRITICAL_SECTION(op);
|
||||||
|
res = stringio_iternext_lock_held(op);
|
||||||
|
Py_END_CRITICAL_SECTION();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
@critical_section
|
@critical_section
|
||||||
_io.StringIO.truncate
|
_io.StringIO.truncate
|
||||||
|
Loading…
x
Reference in New Issue
Block a user