Skip to content

Commit

Permalink
[3.12] gh-127182: Fix io.StringIO.__setstate__ crash when None is…
Browse files Browse the repository at this point in the history
… the first value (GH-127219) (#127263)

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

Co-authored-by: sobolevn <mail@sobolevn.me>
Co-authored-by: Victor Stinner <vstinner@python.org>
  • Loading branch information
3 people authored Nov 25, 2024
1 parent f7e587d commit a4d6b90
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 14 deletions.
15 changes: 15 additions & 0 deletions Lib/test/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix :meth:`!io.StringIO.__setstate__` crash, when :const:`None` was passed as
the first value.
30 changes: 16 additions & 14 deletions Modules/_io/stringio.c
Original file line number Diff line number Diff line change
Expand Up @@ -884,23 +884,25 @@ stringio_setstate(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
Expand Down

0 comments on commit a4d6b90

Please sign in to comment.