summaryrefslogtreecommitdiffstats
path: root/Modules/_io
diff options
context:
space:
mode:
authorInada Naoki <songofacandy@gmail.com>2021-02-21 23:29:30 (GMT)
committerGitHub <noreply@github.com>2021-02-21 23:29:30 (GMT)
commit01806d5beba3d208bb56adba6829097d803bf54f (patch)
tree3d843f7b0c03e7e8b0511a523e0f71251bc587bd /Modules/_io
parent84f7afe65c29330f3ff8e318e054b96554a2dede (diff)
downloadcpython-01806d5beba3d208bb56adba6829097d803bf54f.zip
cpython-01806d5beba3d208bb56adba6829097d803bf54f.tar.gz
cpython-01806d5beba3d208bb56adba6829097d803bf54f.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
Diffstat (limited to 'Modules/_io')
-rw-r--r--Modules/_io/textio.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index f08d14e..03001ec 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -1585,6 +1585,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);
@@ -1642,7 +1644,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);
}
@@ -1651,8 +1656,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)
@@ -1677,6 +1683,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) {
@@ -1696,7 +1710,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;