diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py index 63998a86c45b53..249e0f3ba32f29 100644 --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -5,6 +5,7 @@ import unittest from test import support +from test.support import threading_helper import gc import io @@ -12,6 +13,7 @@ import pickle import sys import weakref +import threading class IntLike: def __init__(self, num): @@ -723,6 +725,22 @@ def test_newline_argument(self): for newline in (None, "", "\n", "\r", "\r\n"): 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, TextIOTestMixin, unittest.TestCase): @@ -890,6 +908,7 @@ def test_setstate(self): self.assertRaises(ValueError, memio.__setstate__, ("closed", "", 0, None)) + class CStringIOPickleTest(PyStringIOPickleTest): UnsupportedOperation = io.UnsupportedOperation diff --git a/Misc/NEWS.d/next/Library/2025-06-11-19-05-49.gh-issue-135410.E89Boi.rst b/Misc/NEWS.d/next/Library/2025-06-11-19-05-49.gh-issue-135410.E89Boi.rst new file mode 100644 index 00000000000000..a5917fba3f7bb9 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-06-11-19-05-49.gh-issue-135410.E89Boi.rst @@ -0,0 +1,2 @@ +Fix a crash when iterating over :class:`io.StringIO` on the :term:`free +threaded ` build. diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c index 9d1bfa3ea05cea..dd97ceac32e3fc 100644 --- a/Modules/_io/stringio.c +++ b/Modules/_io/stringio.c @@ -404,7 +404,7 @@ _io_StringIO_readline_impl(stringio *self, Py_ssize_t size) } static PyObject * -stringio_iternext(PyObject *op) +stringio_iternext_lock_held(PyObject *op) { PyObject *line; stringio *self = stringio_CAST(op); @@ -441,6 +441,16 @@ stringio_iternext(PyObject *op) 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] @critical_section _io.StringIO.truncate pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy