https://github.com/python/cpython/commit/a2f00d401af98063ea80dbf40f43a3160e242bd9
commit: a2f00d401af98063ea80dbf40f43a3160e242bd9
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: vstinner <[email protected]>
date: 2026-06-01T13:26:30Z
summary:

[3.14] gh-149046: fix: correctly handle `str` subclasses in `io.StringIO` 
(GH-149047) (#150707)

gh-149046: fix: correctly handle `str` subclasses in `io.StringIO` (GH-149047)
(cherry picked from commit c98773633c97463e35eb51fac81d1095e8061fe0)

Co-authored-by: Thomas Kowalski <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-04-27-11-12-00.gh-issue-149046.74shDd.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 482b183da23ffa2..3669ac0b038b71b 100644
--- a/Lib/test/test_memoryio.py
+++ b/Lib/test/test_memoryio.py
@@ -967,6 +967,25 @@ def test_setstate(self):
         memio.close()
         self.assertRaises(ValueError, memio.__setstate__, ("closed", "", 0, 
None))
 
+    def test_write_str_subclass(self):
+        # Writing a str subclass should use the subclass's unicode data
+        # directly, not call __str__ on it (which may return a different
+        # value).  gh-149047
+        class MyStr(str):
+            def __str__(self):
+                return "WRONG"
+
+        s = MyStr("correct")
+        memio = self.ioclass()
+        memio.write(s)
+        self.assertEqual(memio.getvalue(), "correct")
+
+        # Also test the fast path where pos == string_size (STATE_ACCUMULATING)
+        memio2 = self.ioclass()
+        memio2.write(MyStr("hello "))
+        memio2.write(MyStr("world"))
+        self.assertEqual(memio2.getvalue(), "hello world")
+
 
 class CStringIOPickleTest(PyStringIOPickleTest):
     UnsupportedOperation = io.UnsupportedOperation
diff --git 
a/Misc/NEWS.d/next/Library/2026-04-27-11-12-00.gh-issue-149046.74shDd.rst 
b/Misc/NEWS.d/next/Library/2026-04-27-11-12-00.gh-issue-149046.74shDd.rst
new file mode 100644
index 000000000000000..b05c4222e30fcd2
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-04-27-11-12-00.gh-issue-149046.74shDd.rst
@@ -0,0 +1,2 @@
+:mod:`io`: Fix :class:`io.StringIO` serialization: no longer call ``str(obj)`` 
on :class:`str`
+subclasses. Patch by Thomas Kowalski.
diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c
index 0070b7c52d94ac8..8f7801dab96dd1d 100644
--- a/Modules/_io/stringio.c
+++ b/Modules/_io/stringio.c
@@ -225,7 +225,9 @@ write_str(stringio *self, PyObject *obj)
 
     if (self->state == STATE_ACCUMULATING) {
         if (self->string_size == self->pos) {
-            if (PyUnicodeWriter_WriteStr(self->writer, decoded))
+            // gh-149046: Avoid PyUnicodeWriter_WriteStr() which calls str(obj)
+            // on str subclasses
+            if (_PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)self->writer, 
decoded))
                 goto fail;
             goto success;
         }

_______________________________________________
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