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 fdb5a50ef3
)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
parent
fd1c092bb9
commit
dedb28efd8
|
@ -826,8 +826,10 @@ stringio_getstate(stringio *self)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dict = PyDict_Copy(self->dict);
|
dict = PyDict_Copy(self->dict);
|
||||||
if (dict == NULL)
|
if (dict == NULL) {
|
||||||
|
Py_DECREF(initvalue);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state = Py_BuildValue("(OOnN)", initvalue,
|
state = Py_BuildValue("(OOnN)", initvalue,
|
||||||
|
|
|
@ -1773,11 +1773,16 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint)
|
||||||
*/
|
*/
|
||||||
PyObject *next_input = dec_buffer;
|
PyObject *next_input = dec_buffer;
|
||||||
PyBytes_Concat(&next_input, input_chunk);
|
PyBytes_Concat(&next_input, input_chunk);
|
||||||
|
dec_buffer = NULL; /* Reference lost to PyBytes_Concat */
|
||||||
if (next_input == NULL) {
|
if (next_input == NULL) {
|
||||||
dec_buffer = NULL; /* Reference lost to PyBytes_Concat */
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
Py_XSETREF(self->snapshot, Py_BuildValue("NN", dec_flags, next_input));
|
PyObject *snapshot = Py_BuildValue("NN", dec_flags, next_input);
|
||||||
|
if (snapshot == NULL) {
|
||||||
|
dec_flags = NULL;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
Py_XSETREF(self->snapshot, snapshot);
|
||||||
}
|
}
|
||||||
Py_DECREF(input_chunk);
|
Py_DECREF(input_chunk);
|
||||||
|
|
||||||
|
@ -2326,6 +2331,7 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
|
||||||
cookie_type cookie;
|
cookie_type cookie;
|
||||||
PyObject *res;
|
PyObject *res;
|
||||||
int cmp;
|
int cmp;
|
||||||
|
PyObject *snapshot;
|
||||||
|
|
||||||
CHECK_ATTACHED(self);
|
CHECK_ATTACHED(self);
|
||||||
CHECK_CLOSED(self);
|
CHECK_CLOSED(self);
|
||||||
|
@ -2460,11 +2466,11 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
self->snapshot = Py_BuildValue("iN", cookie.dec_flags, input_chunk);
|
snapshot = Py_BuildValue("iN", cookie.dec_flags, input_chunk);
|
||||||
if (self->snapshot == NULL) {
|
if (snapshot == NULL) {
|
||||||
Py_DECREF(input_chunk);
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
Py_XSETREF(self->snapshot, snapshot);
|
||||||
|
|
||||||
decoded = _PyObject_CallMethodId(self->decoder, &PyId_decode,
|
decoded = _PyObject_CallMethodId(self->decoder, &PyId_decode,
|
||||||
"Oi", input_chunk, (int)cookie.need_eof);
|
"Oi", input_chunk, (int)cookie.need_eof);
|
||||||
|
@ -2482,9 +2488,10 @@ _io_TextIOWrapper_seek_impl(textio *self, PyObject *cookieObj, int whence)
|
||||||
self->decoded_chars_used = cookie.chars_to_skip;
|
self->decoded_chars_used = cookie.chars_to_skip;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self->snapshot = Py_BuildValue("iy", cookie.dec_flags, "");
|
snapshot = Py_BuildValue("iy", cookie.dec_flags, "");
|
||||||
if (self->snapshot == NULL)
|
if (snapshot == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
Py_XSETREF(self->snapshot, snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Finally, reset the encoder (merely useful for proper BOM handling) */
|
/* Finally, reset the encoder (merely useful for proper BOM handling) */
|
||||||
|
|
Loading…
Reference in New Issue