https://github.com/python/cpython/commit/8cb7d9a8102163387907425dc14b5d629b930e76
commit: 8cb7d9a8102163387907425dc14b5d629b930e76
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2025-06-12T11:36:44Z
summary:

[3.14] gh-135410: use a critical section around `StringIO.__next__` (GH-135412) 
(#135425)

gh-135410: use a critical section around `StringIO.__next__` (GH-135412)
(cherry picked from commit e6c3039cb39e68ae9af9ddcaca341c5af8f9cf23)

Co-authored-by: Peter Bierma <[email protected]>

files:
A Misc/NEWS.d/next/Library/2025-06-11-19-05-49.gh-issue-135410.E89Boi.rst
M Lib/test/test_memoryio.py
M Modules/_io/stringio.c

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 <free threading>` 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

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to