https://github.com/python/cpython/commit/a1b9663c417ec4f2c53cf59b4f6e2c765e48f829
commit: a1b9663c417ec4f2c53cf59b4f6e2c765e48f829
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: sobolevn <[email protected]>
date: 2024-11-25T17:56:42Z
summary:

[3.13] gh-127182: Fix `io.StringIO.__setstate__` crash when `None` is the first 
value (GH-127219) (#127262)

gh-127182: Fix `io.StringIO.__setstate__` crash when `None` is the first value 
(GH-127219)
(cherry picked from commit a2ee89968299fc4f0da4b5a4165025b941213ba5)

Co-authored-by: sobolevn <[email protected]>
Co-authored-by: Victor Stinner <[email protected]>

files:
A Misc/NEWS.d/next/Library/2024-11-24-14-20-17.gh-issue-127182.WmfY2g.rst
M Lib/test/test_io.py
M Modules/_io/stringio.c

diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index aa1b8268592ff7..f1f8ce57668f3b 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -1148,6 +1148,21 @@ def test_disallow_instantiation(self):
         _io = self._io
         support.check_disallow_instantiation(self, _io._BytesIOBuffer)
 
+    def test_stringio_setstate(self):
+        # gh-127182: Calling __setstate__() with invalid arguments must not 
crash
+        obj = self._io.StringIO()
+        with self.assertRaisesRegex(
+            TypeError,
+            'initial_value must be str or None, not int',
+        ):
+            obj.__setstate__((1, '', 0, {}))
+
+        obj.__setstate__((None, '', 0, {}))  # should not crash
+        self.assertEqual(obj.getvalue(), '')
+
+        obj.__setstate__(('', '', 0, {}))
+        self.assertEqual(obj.getvalue(), '')
+
 class PyIOTest(IOTest):
     pass
 
diff --git 
a/Misc/NEWS.d/next/Library/2024-11-24-14-20-17.gh-issue-127182.WmfY2g.rst 
b/Misc/NEWS.d/next/Library/2024-11-24-14-20-17.gh-issue-127182.WmfY2g.rst
new file mode 100644
index 00000000000000..2cc46ca3d33977
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-11-24-14-20-17.gh-issue-127182.WmfY2g.rst
@@ -0,0 +1,2 @@
+Fix :meth:`!io.StringIO.__setstate__` crash, when :const:`None` was passed as
+the first value.
diff --git a/Modules/_io/stringio.c b/Modules/_io/stringio.c
index 6d48bcb552b4bf..e39289a02bda0f 100644
--- a/Modules/_io/stringio.c
+++ b/Modules/_io/stringio.c
@@ -908,23 +908,25 @@ _io_StringIO___setstate___impl(stringio *self, PyObject 
*state)
        once by __init__. So we do not take any chance and replace object's
        buffer completely. */
     {
-        PyObject *item;
-        Py_UCS4 *buf;
-        Py_ssize_t bufsize;
-
-        item = PyTuple_GET_ITEM(state, 0);
-        buf = PyUnicode_AsUCS4Copy(item);
-        if (buf == NULL)
-            return NULL;
-        bufsize = PyUnicode_GET_LENGTH(item);
+        PyObject *item = PyTuple_GET_ITEM(state, 0);
+        if (PyUnicode_Check(item)) {
+            Py_UCS4 *buf = PyUnicode_AsUCS4Copy(item);
+            if (buf == NULL)
+                return NULL;
+            Py_ssize_t bufsize = PyUnicode_GET_LENGTH(item);
 
-        if (resize_buffer(self, bufsize) < 0) {
+            if (resize_buffer(self, bufsize) < 0) {
+                PyMem_Free(buf);
+                return NULL;
+            }
+            memcpy(self->buf, buf, bufsize * sizeof(Py_UCS4));
             PyMem_Free(buf);
-            return NULL;
+            self->string_size = bufsize;
+        }
+        else {
+            assert(item == Py_None);
+            self->string_size = 0;
         }
-        memcpy(self->buf, buf, bufsize * sizeof(Py_UCS4));
-        PyMem_Free(buf);
-        self->string_size = bufsize;
     }
 
     /* Set carefully the position value. Alternatively, we could use the seek

_______________________________________________
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