Skip to content

Commit e5153d0

Browse files
bpo-25862: Fix several bugs in the _io module. (GH-8026)
They can be exposed when some C API calls fail due to lack of memory. * Failed Py_BuildValue() could cause an assertion error in the following TextIOWrapper.tell(). * input_chunk could be decrefed twice in TextIOWrapper.seek() after failed Py_BuildValue(). * initvalue could leak in StringIO.__getstate__() after failed PyDict_Copy(). (cherry picked from commit fdb5a50) Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent db7ac30 commit e5153d0

2 files changed

Lines changed: 17 additions & 8 deletions

File tree

Modules/_io/stringio.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -870,8 +870,10 @@ stringio_getstate(stringio *self)
870870
}
871871
else {
872872
dict = PyDict_Copy(self->dict);
873-
if (dict == NULL)
873+
if (dict == NULL) {
874+
Py_DECREF(initvalue);
874875
return NULL;
876+
}
875877
}
876878

877879
state = Py_BuildValue("(OOnN)", initvalue,

Modules/_io/textio.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,11 +1540,16 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint)
15401540
*/
15411541
PyObject *next_input = dec_buffer;
15421542
PyBytes_Concat(&next_input, input_chunk);
1543+
dec_buffer = NULL; /* Reference lost to PyBytes_Concat */
15431544
if (next_input == NULL) {
1544-
dec_buffer = NULL; /* Reference lost to PyBytes_Concat */
15451545
goto fail;
15461546
}
1547-
Py_XSETREF(self->snapshot, Py_BuildValue("NN", dec_flags, next_input));
1547+
PyObject *snapshot = Py_BuildValue("NN", dec_flags, next_input);
1548+
if (snapshot == NULL) {
1549+
dec_flags = NULL;
1550+
goto fail;
1551+
}
1552+
Py_XSETREF(self->snapshot, snapshot);
15481553
}
15491554
Py_DECREF(input_chunk);
15501555

@@ -2093,6 +2098,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
20932098
cookie_type cookie;
20942099
PyObject *res;
20952100
int cmp;
2101+
PyObject *snapshot;
20962102

20972103
CHECK_ATTACHED(self);
20982104
CHECK_CLOSED(self);
@@ -2227,11 +2233,11 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
22272233
goto fail;
22282234
}
22292235

2230-
self->snapshot = Py_BuildValue("iN", cookie.dec_flags, input_chunk);
2231-
if (self->snapshot == NULL) {
2232-
Py_DECREF(input_chunk);
2236+
snapshot = Py_BuildValue("iN", cookie.dec_flags, input_chunk);
2237+
if (snapshot == NULL) {
22332238
goto fail;
22342239
}
2240+
Py_XSETREF(self->snapshot, snapshot);
22352241

22362242
decoded = _PyObject_CallMethodId(self->decoder, &PyId_decode,
22372243
"Oi", input_chunk, (int)cookie.need_eof);
@@ -2249,9 +2255,10 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
22492255
self->decoded_chars_used = cookie.chars_to_skip;
22502256
}
22512257
else {
2252-
self->snapshot = Py_BuildValue("iy", cookie.dec_flags, "");
2253-
if (self->snapshot == NULL)
2258+
snapshot = Py_BuildValue("iy", cookie.dec_flags, "");
2259+
if (snapshot == NULL)
22542260
goto fail;
2261+
Py_XSETREF(self->snapshot, snapshot);
22552262
}
22562263

22572264
/* Finally, reset the encoder (merely useful for proper BOM handling) */

0 commit comments

Comments
 (0)