summaryrefslogtreecommitdiffstats
path: root/Modules/_io
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2011-08-20 12:52:04 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2011-08-20 12:52:04 (GMT)
commite8bb1a0229c2aa5a60fe36937d04454bbd3745e4 (patch)
tree99e1690378cae7451f4008ca91561ef1225a9a54 /Modules/_io
parent8fd544ffa926a479c8d80e245e3daf12197aa7a2 (diff)
parente05565ec5af6b326e9d1f17c3f79bc24bf1ee157 (diff)
downloadcpython-e8bb1a0229c2aa5a60fe36937d04454bbd3745e4.zip
cpython-e8bb1a0229c2aa5a60fe36937d04454bbd3745e4.tar.gz
cpython-e8bb1a0229c2aa5a60fe36937d04454bbd3745e4.tar.bz2
Issue #12213: Fix a buffering bug with interleaved reads and writes that
could appear on BufferedRandom streams.
Diffstat (limited to 'Modules/_io')
-rw-r--r--Modules/_io/bufferedio.c101
1 files changed, 57 insertions, 44 deletions
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index cdaa36e..a8631e0 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -753,25 +753,38 @@ _trap_eintr(void)
*/
static PyObject *
-buffered_flush(buffered *self, PyObject *args)
+buffered_flush_and_rewind_unlocked(buffered *self)
{
PyObject *res;
- CHECK_INITIALIZED(self)
- CHECK_CLOSED(self, "flush of closed file")
-
- if (!ENTER_BUFFERED(self))
- return NULL;
res = _bufferedwriter_flush_unlocked(self, 0);
- if (res != NULL && self->readable) {
+ if (res == NULL)
+ return NULL;
+ Py_DECREF(res);
+
+ if (self->readable) {
/* Rewind the raw stream so that its position corresponds to
the current logical position. */
Py_off_t n;
n = _buffered_raw_seek(self, -RAW_OFFSET(self), 1);
- if (n == -1)
- Py_CLEAR(res);
_bufferedreader_reset_buf(self);
+ if (n == -1)
+ return NULL;
}
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+buffered_flush(buffered *self, PyObject *args)
+{
+ PyObject *res;
+
+ CHECK_INITIALIZED(self)
+ CHECK_CLOSED(self, "flush of closed file")
+
+ if (!ENTER_BUFFERED(self))
+ return NULL;
+ res = buffered_flush_and_rewind_unlocked(self);
LEAVE_BUFFERED(self)
return res;
@@ -792,7 +805,7 @@ buffered_peek(buffered *self, PyObject *args)
return NULL;
if (self->writable) {
- res = _bufferedwriter_flush_unlocked(self, 1);
+ res = buffered_flush_and_rewind_unlocked(self);
if (res == NULL)
goto end;
Py_CLEAR(res);
@@ -827,19 +840,18 @@ buffered_read(buffered *self, PyObject *args)
if (!ENTER_BUFFERED(self))
return NULL;
res = _bufferedreader_read_all(self);
- LEAVE_BUFFERED(self)
}
else {
res = _bufferedreader_read_fast(self, n);
- if (res == Py_None) {
- Py_DECREF(res);
- if (!ENTER_BUFFERED(self))
- return NULL;
- res = _bufferedreader_read_generic(self, n);
- LEAVE_BUFFERED(self)
- }
+ if (res != Py_None)
+ return res;
+ Py_DECREF(res);
+ if (!ENTER_BUFFERED(self))
+ return NULL;
+ res = _bufferedreader_read_generic(self, n);
}
+ LEAVE_BUFFERED(self)
return res;
}
@@ -865,13 +877,6 @@ buffered_read1(buffered *self, PyObject *args)
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. */
@@ -891,6 +896,13 @@ buffered_read1(buffered *self, PyObject *args)
goto end;
}
+ if (self->writable) {
+ res = buffered_flush_and_rewind_unlocked(self);
+ if (res == NULL)
+ goto end;
+ Py_DECREF(res);
+ }
+
/* Fill the buffer from the raw stream, and copy it to the result. */
_bufferedreader_reset_buf(self);
r = _bufferedreader_fill_buffer(self);
@@ -939,7 +951,7 @@ buffered_readinto(buffered *self, PyObject *args)
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);
@@ -1022,12 +1034,6 @@ _buffered_readline(buffered *self, Py_ssize_t limit)
goto end_unlocked;
/* Now we try to get some more from the raw stream */
- if (self->writable) {
- res = _bufferedwriter_flush_unlocked(self, 1);
- if (res == NULL)
- goto end;
- Py_CLEAR(res);
- }
chunks = PyList_New(0);
if (chunks == NULL)
goto end;
@@ -1041,9 +1047,16 @@ _buffered_readline(buffered *self, Py_ssize_t limit)
}
Py_CLEAR(res);
written += n;
+ self->pos += n;
if (limit >= 0)
limit -= n;
}
+ if (self->writable) {
+ PyObject *r = buffered_flush_and_rewind_unlocked(self);
+ if (r == NULL)
+ goto end;
+ Py_DECREF(r);
+ }
for (;;) {
_bufferedreader_reset_buf(self);
@@ -1212,20 +1225,11 @@ buffered_truncate(buffered *self, PyObject *args)
return NULL;
if (self->writable) {
- res = _bufferedwriter_flush_unlocked(self, 0);
+ res = buffered_flush_and_rewind_unlocked(self);
if (res == NULL)
goto end;
Py_CLEAR(res);
}
- if (self->readable) {
- if (pos == Py_None) {
- /* Rewind the raw stream so that its position corresponds to
- the current logical position. */
- if (_buffered_raw_seek(self, -RAW_OFFSET(self), 1) == -1)
- goto end;
- }
- _bufferedreader_reset_buf(self);
- }
res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_truncate, pos, NULL);
if (res == NULL)
goto end;
@@ -1416,15 +1420,16 @@ _bufferedreader_read_all(buffered *self)
self->buffer + self->pos, current_size);
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)
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);
@@ -1540,6 +1545,14 @@ _bufferedreader_read_generic(buffered *self, Py_ssize_t n)
memcpy(out, self->buffer + self->pos, current_size);
remaining -= current_size;
written += current_size;
+ self->pos += current_size;
+ }
+ /* Flush the write buffer if necessary */
+ if (self->writable) {
+ PyObject *r = buffered_flush_and_rewind_unlocked(self);
+ if (r == NULL)
+ goto error;
+ Py_DECREF(r);
}
_bufferedreader_reset_buf(self);
while (remaining > 0) {