summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_io.py20
-rw-r--r--Misc/NEWS5
-rw-r--r--Modules/_io/bufferedio.c13
3 files changed, 38 insertions, 0 deletions
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index 1f1cba2..a9094d9 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -1328,6 +1328,26 @@ class BufferedRandomTest(BufferedReaderTest, BufferedWriterTest):
bufio.readinto(bytearray(1))
self.check_writes(_read)
+ def test_write_after_readahead(self):
+ # Issue #6629: writing after the buffer was filled by readahead should
+ # first rewind the raw stream.
+ for overwrite_size in [1, 5]:
+ raw = self.BytesIO(b"A" * 10)
+ bufio = self.tp(raw, 4)
+ # Trigger readahead
+ self.assertEqual(bufio.read(1), b"A")
+ self.assertEqual(bufio.tell(), 1)
+ # Overwriting should rewind the raw stream if it needs so
+ bufio.write(b"B" * overwrite_size)
+ self.assertEqual(bufio.tell(), overwrite_size + 1)
+ # If the write size was smaller than the buffer size, flush() and
+ # check that rewind happens.
+ bufio.flush()
+ self.assertEqual(bufio.tell(), overwrite_size + 1)
+ s = raw.getvalue()
+ self.assertEqual(s,
+ b"A" + b"B" * overwrite_size + b"A" * (9 - overwrite_size))
+
def test_misbehaved_io(self):
BufferedReaderTest.test_misbehaved_io(self)
BufferedWriterTest.test_misbehaved_io(self)
diff --git a/Misc/NEWS b/Misc/NEWS
index bf70fc8..9ae93aa 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -63,6 +63,11 @@ C-API
Library
-------
+- Issue #6629: Fix a data corruption issue in the new I/O library, which could
+ occur when writing to a BufferedRandom object (e.g. a file opened in "rb+" or
+ "wb+" mode) after having buffered a certain amount of data for reading. This
+ bug was not present in the pure Python implementation.
+
- Issue #6622: Fix "local variable 'secret' referenced before
assignment" bug in POP3.apop.
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index 98f8413..d8b6471 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -1757,6 +1757,19 @@ bufferedwriter_write(buffered *self, PyObject *args)
}
Py_CLEAR(res);
+ /* Adjust the raw stream position if it is away from the logical stream
+ position. This happens if the read buffer has been filled but not
+ modified (and therefore _bufferedwriter_flush_unlocked() didn't rewind
+ the raw stream by itself).
+ Fixes issue #6629.
+ */
+ n = RAW_OFFSET(self);
+ if (n != 0) {
+ if (_buffered_raw_seek(self, -n, 1) < 0)
+ goto error;
+ self->raw_pos -= n;
+ }
+
/* Then write buf itself. At this point the buffer has been emptied. */
remaining = buf.len;
written = 0;