summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_io.py15
-rw-r--r--Misc/NEWS.d/next/Library/2024-11-24-14-20-17.gh-issue-127182.WmfY2g.rst2
-rw-r--r--Modules/_io/stringio.c30
3 files changed, 33 insertions, 14 deletions
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index aa1b826..f1f8ce5 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -1148,6 +1148,21 @@ class TestIOCTypes(unittest.TestCase):
_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 0000000..2cc46ca
--- /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 f558613..65e8d97 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