Skip to content

Commit fdb5a50

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().
1 parent 0cdf5f4 commit fdb5a50

File tree

2 files changed

+17
-8
lines changed

2 files changed

+17
-8
lines changed

Modules/_io/stringio.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,8 +826,10 @@ stringio_getstate(stringio *self, PyObject *Py_UNUSED(ignored))
826826
}
827827
else {
828828
dict = PyDict_Copy(self->dict);
829-
if (dict == NULL)
829+
if (dict == NULL) {
830+
Py_DECREF(initvalue);
830831
return NULL;
832+
}
831833
}
832834

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

Modules/_io/textio.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1773,11 +1773,16 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint)
17731773
*/
17741774
PyObject *next_input = dec_buffer;
17751775
PyBytes_Concat(&next_input, input_chunk);
1776+
dec_buffer = NULL; /* Reference lost to PyBytes_Concat */
17761777
if (next_input == NULL) {
1777-
dec_buffer = NULL; /* Reference lost to PyBytes_Concat */
17781778
goto fail;
17791779
}
1780-
Py_XSETREF(self->snapshot, Py_BuildValue("NN", dec_flags, next_input));
1780+
PyObject *snapshot = Py_BuildValue("NN", dec_flags, next_input);
1781+
if (snapshot == NULL) {
1782+
dec_flags = NULL;
1783+
goto fail;
1784+
}
1785+
Py_XSETREF(self->snapshot, snapshot);
17811786
}
17821787
Py_DECREF(input_chunk);
17831788

@@ -2326,6 +2331,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
23262331
cookie_type cookie;
23272332
PyObject *res;
23282333
int cmp;
2334+
PyObject *snapshot;
23292335

23302336
CHECK_ATTACHED(self);
23312337
CHECK_CLOSED(self);
@@ -2460,11 +2466,11 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
24602466
goto fail;
24612467
}
24622468

2463-
self->snapshot = Py_BuildValue("iN", cookie.dec_flags, input_chunk);
2464-
if (self->snapshot == NULL) {
2465-
Py_DECREF(input_chunk);
2469+
snapshot = Py_BuildValue("iN", cookie.dec_flags, input_chunk);
2470+
if (snapshot == NULL) {
24662471
goto fail;
24672472
}
2473+
Py_XSETREF(self->snapshot, snapshot);
24682474

24692475
decoded = _PyObject_CallMethodId(self->decoder, &PyId_decode,
24702476
"Oi", input_chunk, (int)cookie.need_eof);
@@ -2482,9 +2488,10 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
24822488
self->decoded_chars_used = cookie.chars_to_skip;
24832489
}
24842490
else {
2485-
self->snapshot = Py_BuildValue("iy", cookie.dec_flags, "");
2486-
if (self->snapshot == NULL)
2491+
snapshot = Py_BuildValue("iy", cookie.dec_flags, "");
2492+
if (snapshot == NULL)
24872493
goto fail;
2494+
Py_XSETREF(self->snapshot, snapshot);
24882495
}
24892496

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

0 commit comments

Comments
 (0)