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:
Miss Islington (bot) 2018-06-30 11:25:37 -07:00 committed by GitHub
parent fd1c092bb9
commit dedb28efd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 17 additions and 8 deletions

View File

@ -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,

View File

@ -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) */