aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornechda <nechda@yandex-team.com>2024-08-04 13:43:56 +0300
committernechda <nechda@yandex-team.com>2024-08-04 13:53:51 +0300
commite30f7061bad712a7934e383fef27613fc6a1b2d7 (patch)
treefed6a6490d45ffd04aca8a0d6a36e6c198ddb53e
parent55c4d6e43a8d293d088b2501098a802a40cade9a (diff)
downloadydb-e30f7061bad712a7934e383fef27613fc6a1b2d7.tar.gz
fix _io.TextIOWrapper.write() write during flush
816f3097d548522bcfae2b763098747304285d0f
-rw-r--r--contrib/tools/python3/Modules/_io/textio.c31
1 files changed, 22 insertions, 9 deletions
diff --git a/contrib/tools/python3/Modules/_io/textio.c b/contrib/tools/python3/Modules/_io/textio.c
index 14dd19d95c..4a1ba22d38 100644
--- a/contrib/tools/python3/Modules/_io/textio.c
+++ b/contrib/tools/python3/Modules/_io/textio.c
@@ -1723,16 +1723,26 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text)
bytes_len = PyBytes_GET_SIZE(b);
}
- if (self->pending_bytes == NULL) {
- 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;
+ // We should avoid concatinating huge data.
+ // Flush the buffer before adding b to the buffer if b is not small.
+ // https://github.com/python/cpython/issues/87426
+ if (bytes_len >= self->chunk_size) {
+ // _textiowrapper_writeflush() calls buffer.write().
+ // self->pending_bytes can be appended during buffer->write()
+ // or other thread.
+ // We need to loop until buffer becomes empty.
+ // https://github.com/python/cpython/issues/118138
+ // https://github.com/python/cpython/issues/119506
+ while (self->pending_bytes != NULL) {
+ if (_textiowrapper_writeflush(self) < 0) {
+ Py_DECREF(b);
+ return NULL;
+ }
}
+ }
+
+ if (self->pending_bytes == NULL) {
+ assert(self->pending_bytes_count == 0);
self->pending_bytes = b;
}
else if (!PyList_CheckExact(self->pending_bytes)) {
@@ -1741,6 +1751,9 @@ _io_TextIOWrapper_write_impl(textio *self, PyObject *text)
Py_DECREF(b);
return NULL;
}
+ // Since Python 3.12, allocating GC object won't trigger GC and release
+ // GIL. See https://github.com/python/cpython/issues/97922
+ assert(!PyList_CheckExact(self->pending_bytes));
PyList_SET_ITEM(list, 0, self->pending_bytes);
PyList_SET_ITEM(list, 1, b);
self->pending_bytes = list;