Issue #12062: In the `io` module, fix a flushing bug when doing a certain

type of I/O sequence on a file opened in read+write mode (namely: reading,
seeking a bit forward, writing, then seeking before the previous write but
still within buffered data, and writing again).
This commit is contained in:
Antoine Pitrou 2011-05-13 00:31:52 +02:00
parent 073070629b
commit ee46a7bf9c
3 changed files with 32 additions and 1 deletions

View File

@ -1462,6 +1462,32 @@ class BufferedRandomTest(BufferedReaderTest, BufferedWriterTest):
self.assertEqual(s, self.assertEqual(s,
b"A" + b"B" * overwrite_size + b"A" * (9 - overwrite_size)) b"A" + b"B" * overwrite_size + b"A" * (9 - overwrite_size))
def test_write_rewind_write(self):
# Various combinations of reading / writing / seeking backwards / writing again
def mutate(bufio, pos1, pos2):
assert pos2 >= pos1
# Fill the buffer
bufio.seek(pos1)
bufio.read(pos2 - pos1)
bufio.write(b'\x02')
# This writes earlier than the previous write, but still inside
# the buffer.
bufio.seek(pos1)
bufio.write(b'\x01')
b = b"\x80\x81\x82\x83\x84"
for i in range(0, len(b)):
for j in range(i, len(b)):
raw = self.BytesIO(b)
bufio = self.tp(raw, 100)
mutate(bufio, i, j)
bufio.flush()
expected = bytearray(b)
expected[j] = 2
expected[i] = 1
self.assertEqual(raw.getvalue(), expected,
"failed result for i=%d, j=%d" % (i, j))
def test_truncate_after_read_or_write(self): def test_truncate_after_read_or_write(self):
raw = self.BytesIO(b"A" * 10) raw = self.BytesIO(b"A" * 10)
bufio = self.tp(raw, 100) bufio = self.tp(raw, 100)

View File

@ -80,6 +80,11 @@ Core and Builtins
Library Library
------- -------
- Issue #12062: In the `io` module, fix a flushing bug when doing a certain
type of I/O sequence on a file opened in read+write mode (namely: reading,
seeking a bit forward, writing, then seeking before the previous write but
still within buffered data, and writing again).
- Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in - Issue #8498: In socket.accept(), allow to specify 0 as a backlog value in
order to accept exactly one connection. Patch by Daniel Evers. order to accept exactly one connection. Patch by Daniel Evers.

View File

@ -1810,7 +1810,7 @@ bufferedwriter_write(buffered *self, PyObject *args)
avail = Py_SAFE_DOWNCAST(self->buffer_size - self->pos, Py_off_t, Py_ssize_t); avail = Py_SAFE_DOWNCAST(self->buffer_size - self->pos, Py_off_t, Py_ssize_t);
if (buf.len <= avail) { if (buf.len <= avail) {
memcpy(self->buffer + self->pos, buf.buf, buf.len); memcpy(self->buffer + self->pos, buf.buf, buf.len);
if (!VALID_WRITE_BUFFER(self)) { if (!VALID_WRITE_BUFFER(self) || self->write_pos > self->pos) {
self->write_pos = self->pos; self->write_pos = self->pos;
} }
ADJUST_POSITION(self, self->pos + buf.len); ADJUST_POSITION(self, self->pos + buf.len);