summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2011-05-12 22:25:53 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2011-05-12 22:25:53 (GMT)
commitb89b31a1588b78f9c08ed8b4f5519571c2a44a42 (patch)
treeb0b6151b7bb16c5835fc0049b02e140931365532
parent30536d1b77f78a049621d0fee873324be95b393a (diff)
parent00dd182b8ec1629a35cb6e9d551dedff6b7149f7 (diff)
downloadcpython-b89b31a1588b78f9c08ed8b4f5519571c2a44a42.zip
cpython-b89b31a1588b78f9c08ed8b4f5519571c2a44a42.tar.gz
cpython-b89b31a1588b78f9c08ed8b4f5519571c2a44a42.tar.bz2
Issue #12062: 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).
-rw-r--r--Lib/test/test_io.py26
-rw-r--r--Misc/NEWS5
-rw-r--r--Modules/_io/bufferedio.c2
3 files changed, 32 insertions, 1 deletions
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 153548e..3724b5c 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -1496,6 +1496,32 @@ class BufferedRandomTest(BufferedReaderTest, BufferedWriterTest):
self.assertEqual(s,
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):
raw = self.BytesIO(b"A" * 10)
bufio = self.tp(raw, 100)
diff --git a/Misc/NEWS b/Misc/NEWS
index 751f1e3..620d3d6 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -147,6 +147,11 @@ Core and Builtins
Library
-------
+- Issue #12062: 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 #9971: Write an optimized implementation of BufferedReader.readinto().
Patch by John O'Connor.
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index dfe593f..3b8b7e9 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -1894,7 +1894,7 @@ bufferedwriter_write(buffered *self, PyObject *args)
avail = Py_SAFE_DOWNCAST(self->buffer_size - self->pos, Py_off_t, Py_ssize_t);
if (buf.len <= avail) {
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;
}
ADJUST_POSITION(self, self->pos + buf.len);