From: Antoine Pitrou Date: Sat, 20 Aug 2011 12:52:04 +0000 (+0200) Subject: Issue #12213: Fix a buffering bug with interleaved reads and writes that X-Git-Tag: v3.3.0a1~1665 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e8bb1a0229c2aa5a60fe36937d04454bbd3745e4;p=thirdparty%2FPython%2Fcpython.git Issue #12213: Fix a buffering bug with interleaved reads and writes that could appear on BufferedRandom streams. --- e8bb1a0229c2aa5a60fe36937d04454bbd3745e4 diff --cc Misc/NEWS index 7dc106afee10,da0e67f666c4..29a2e6f924a7 --- a/Misc/NEWS +++ b/Misc/NEWS @@@ -265,18 -70,6 +265,21 @@@ Core and Builtin Library ------- ++- Issue #12213: Fix a buffering bug with interleaved reads and writes that ++ could appear on BufferedRandom streams. ++ +- Issue #12778: Reduce memory consumption when JSON-encoding a large + container of many small objects. + +- Issue #12650: Fix a race condition where a subprocess.Popen could leak + resources (FD/zombie) when killed at the wrong time. + +- Issue #12744: Fix inefficient representation of integers between 2**31 and + 2**63 on systems with a 64-bit C "long". + +- Issue #12646: Add an 'eof' attribute to zlib.Decompress, to make it easier to + detect truncated input streams. + - Issue #11513: Fix exception handling ``tarfile.TarFile.gzopen()`` when the file cannot be opened. diff --cc Modules/_io/bufferedio.c index cdaa36e3a777,d6f0c9cc8350..a8631e0bc61d --- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@@ -864,14 -875,7 +876,7 @@@ buffered_read1(buffered *self, PyObjec if (!ENTER_BUFFERED(self)) return NULL; - + - if (self->writable) { - res = _bufferedwriter_flush_unlocked(self, 1); - if (res == NULL) - goto end; - Py_CLEAR(res); - } - /* Return up to n bytes. If at least one byte is buffered, we only return buffered bytes. Otherwise, we do one raw read. */ @@@ -913,78 -924,10 +925,78 @@@ end static PyObject * buffered_readinto(buffered *self, PyObject *args) { + Py_buffer buf; + Py_ssize_t n, written = 0, remaining; + PyObject *res = NULL; + CHECK_INITIALIZED(self) - - /* TODO: use raw.readinto() (or a direct copy from our buffer) instead! */ - return bufferediobase_readinto((PyObject *)self, args); + + if (!PyArg_ParseTuple(args, "w*:readinto", &buf)) + return NULL; + + n = Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t); + if (n > 0) { + if (n >= buf.len) { + memcpy(buf.buf, self->buffer + self->pos, buf.len); + self->pos += buf.len; + res = PyLong_FromSsize_t(buf.len); + goto end_unlocked; + } + memcpy(buf.buf, self->buffer + self->pos, n); + self->pos += n; + written = n; + } + + if (!ENTER_BUFFERED(self)) + goto end_unlocked; + + if (self->writable) { - res = _bufferedwriter_flush_unlocked(self, 0); ++ res = buffered_flush_and_rewind_unlocked(self); + if (res == NULL) + goto end; + Py_CLEAR(res); + } + + _bufferedreader_reset_buf(self); + self->pos = 0; + + for (remaining = buf.len - written; + remaining > 0; + written += n, remaining -= n) { + /* If remaining bytes is larger than internal buffer size, copy + * directly into caller's buffer. */ + if (remaining > self->buffer_size) { + n = _bufferedreader_raw_read(self, (char *) buf.buf + written, + remaining); + } + else { + n = _bufferedreader_fill_buffer(self); + if (n > 0) { + if (n > remaining) + n = remaining; + memcpy((char *) buf.buf + written, + self->buffer + self->pos, n); + self->pos += n; + continue; /* short circuit */ + } + } + if (n == 0 || (n == -2 && written > 0)) + break; + if (n < 0) { + if (n == -2) { + Py_INCREF(Py_None); + res = Py_None; + } + goto end; + } + } + res = PyLong_FromSsize_t(written); + +end: + LEAVE_BUFFERED(self); +end_unlocked: + PyBuffer_Release(&buf); + return res; } static PyObject * @@@ -1414,50 -1353,22 +1418,51 @@@ _bufferedreader_read_all(buffered *self if (current_size) { data = PyBytes_FromStringAndSize( self->buffer + self->pos, current_size); - if (data == NULL) { - Py_DECREF(chunks); + if (data == NULL) return NULL; - } + self->pos += current_size; } - _bufferedreader_reset_buf(self); /* We're going past the buffer's bounds, flush it */ if (self->writable) { - res = _bufferedwriter_flush_unlocked(self, 1); + res = buffered_flush_and_rewind_unlocked(self); - if (res == NULL) { - Py_DECREF(chunks); + if (res == NULL) return NULL; - } Py_CLEAR(res); } + _bufferedreader_reset_buf(self); + + if (PyObject_HasAttr(self->raw, _PyIO_str_readall)) { + chunk = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readall, NULL); + if (chunk == NULL) + return NULL; + if (chunk != Py_None && !PyBytes_Check(chunk)) { + Py_XDECREF(data); + Py_DECREF(chunk); + PyErr_SetString(PyExc_TypeError, "readall() should return bytes"); + return NULL; + } + if (chunk == Py_None) { + if (current_size == 0) + return chunk; + else { + Py_DECREF(chunk); + return data; + } + } + else if (current_size) { + PyBytes_Concat(&data, chunk); + Py_DECREF(chunk); + if (data == NULL) + return NULL; + return data; + } else + return chunk; + } + + chunks = PyList_New(0); + if (chunks == NULL) + return NULL; + while (1) { if (data) { if (PyList_Append(chunks, data) < 0) {