diff options
author | Inada Naoki <songofacandy@gmail.com> | 2021-02-22 01:32:55 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-22 01:32:55 (GMT) |
commit | d51436f95bf5978f82d917e53e9a456fdaa83a9d (patch) | |
tree | 079850b8608542c44004cb085438270a6d77b997 /Modules/_io | |
parent | 44fe32061d60f4bd9c4fa48c24e3e4ba26033dba (diff) | |
download | cpython-d51436f95bf5978f82d917e53e9a456fdaa83a9d.zip cpython-d51436f95bf5978f82d917e53e9a456fdaa83a9d.tar.gz cpython-d51436f95bf5978f82d917e53e9a456fdaa83a9d.tar.bz2 |
bpo-43260: io: Prevent large data remains in textio buffer. (GH-24592)
When very large data remains in TextIOWrapper, flush() may fail forever.
So prevent that data larger than chunk_size is remained in TextIOWrapper internal
buffer.
Co-Authored-By: Eryk Sun
(cherry picked from commit 01806d5)
Diffstat (limited to 'Modules/_io')
-rw-r--r-- | Modules/_io/textio.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index f2c72eb..966c532 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1602,6 +1602,8 @@ _textiowrapper_writeflush(textio *self) ret = PyObject_CallMethodOneArg(self->buffer, _PyIO_str_write, b); } while (ret == NULL && _PyIO_trap_eintr()); Py_DECREF(b); + // NOTE: We cleared buffer but we don't know how many bytes are actually written + // when an error occurred. if (ret == NULL) return -1; Py_DECREF(ret); @@ -1659,7 +1661,10 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text) /* XXX What if we were just reading? */ if (self->encodefunc != NULL) { - if (PyUnicode_IS_ASCII(text) && is_asciicompat_encoding(self->encodefunc)) { + if (PyUnicode_IS_ASCII(text) && + // See bpo-43260 + PyUnicode_GET_LENGTH(text) <= self->chunk_size && + is_asciicompat_encoding(self->encodefunc)) { b = text; Py_INCREF(b); } @@ -1668,8 +1673,9 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text) } self->encoding_start_of_stream = 0; } - else + else { b = PyObject_CallMethodOneArg(self->encoder, _PyIO_str_encode, text); + } Py_DECREF(text); if (b == NULL) @@ -1694,6 +1700,14 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text) self->pending_bytes_count = 0; self->pending_bytes = b; } + else if (self->pending_bytes_count + bytes_len > self->chunk_size) { + // Prevent to concatenate more than chunk_size data. + if (_textiowrapper_writeflush(self) < 0) { + Py_DECREF(b); + return NULL; + } + self->pending_bytes = b; + } else if (!PyList_CheckExact(self->pending_bytes)) { PyObject *list = PyList_New(2); if (list == NULL) { @@ -1713,7 +1727,7 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text) } self->pending_bytes_count += bytes_len; - if (self->pending_bytes_count > self->chunk_size || needflush || + if (self->pending_bytes_count >= self->chunk_size || needflush || text_needflush) { if (_textiowrapper_writeflush(self) < 0) return NULL; |