Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a2ee899

Browse filesBrowse files
sobolevnvstinner
andauthored
gh-127182: Fix io.StringIO.__setstate__ crash when None is the first value (#127219)
Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent d3da04b commit a2ee899
Copy full SHA for a2ee899

File tree

3 files changed

+33
-14
lines changed
Filter options

3 files changed

+33
-14
lines changed

‎Lib/test/test_io.py

Copy file name to clipboardExpand all lines: Lib/test/test_io.py
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,21 @@ def test_disallow_instantiation(self):
11481148
_io = self._io
11491149
support.check_disallow_instantiation(self, _io._BytesIOBuffer)
11501150

1151+
def test_stringio_setstate(self):
1152+
# gh-127182: Calling __setstate__() with invalid arguments must not crash
1153+
obj = self._io.StringIO()
1154+
with self.assertRaisesRegex(
1155+
TypeError,
1156+
'initial_value must be str or None, not int',
1157+
):
1158+
obj.__setstate__((1, '', 0, {}))
1159+
1160+
obj.__setstate__((None, '', 0, {})) # should not crash
1161+
self.assertEqual(obj.getvalue(), '')
1162+
1163+
obj.__setstate__(('', '', 0, {}))
1164+
self.assertEqual(obj.getvalue(), '')
1165+
11511166
class PyIOTest(IOTest):
11521167
pass
11531168

+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :meth:`!io.StringIO.__setstate__` crash, when :const:`None` was passed as
2+
the first value.

‎Modules/_io/stringio.c

Copy file name to clipboardExpand all lines: Modules/_io/stringio.c
+16-14Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -908,23 +908,25 @@ _io_StringIO___setstate___impl(stringio *self, PyObject *state)
908908
once by __init__. So we do not take any chance and replace object's
909909
buffer completely. */
910910
{
911-
PyObject *item;
912-
Py_UCS4 *buf;
913-
Py_ssize_t bufsize;
914-
915-
item = PyTuple_GET_ITEM(state, 0);
916-
buf = PyUnicode_AsUCS4Copy(item);
917-
if (buf == NULL)
918-
return NULL;
919-
bufsize = PyUnicode_GET_LENGTH(item);
911+
PyObject *item = PyTuple_GET_ITEM(state, 0);
912+
if (PyUnicode_Check(item)) {
913+
Py_UCS4 *buf = PyUnicode_AsUCS4Copy(item);
914+
if (buf == NULL)
915+
return NULL;
916+
Py_ssize_t bufsize = PyUnicode_GET_LENGTH(item);
920917

921-
if (resize_buffer(self, bufsize) < 0) {
918+
if (resize_buffer(self, bufsize) < 0) {
919+
PyMem_Free(buf);
920+
return NULL;
921+
}
922+
memcpy(self->buf, buf, bufsize * sizeof(Py_UCS4));
922923
PyMem_Free(buf);
923-
return NULL;
924+
self->string_size = bufsize;
925+
}
926+
else {
927+
assert(item == Py_None);
928+
self->string_size = 0;
924929
}
925-
memcpy(self->buf, buf, bufsize * sizeof(Py_UCS4));
926-
PyMem_Free(buf);
927-
self->string_size = bufsize;
928930
}
929931

930932
/* Set carefully the position value. Alternatively, we could use the seek

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.