mirror of https://github.com/python/cpython
Issue #6629: Fix a data corruption issue in the new `io` package, 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. Yes, this is a serious issue.
This commit is contained in:
parent
4a46e1c4b3
commit
20e1f932fa
|
@ -1336,6 +1336,26 @@ class BufferedRandomTest(BufferedReaderTest, BufferedWriterTest):
|
||||||
bufio.readinto(bytearray(1))
|
bufio.readinto(bytearray(1))
|
||||||
self.check_writes(_read)
|
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):
|
def test_misbehaved_io(self):
|
||||||
BufferedReaderTest.test_misbehaved_io(self)
|
BufferedReaderTest.test_misbehaved_io(self)
|
||||||
BufferedWriterTest.test_misbehaved_io(self)
|
BufferedWriterTest.test_misbehaved_io(self)
|
||||||
|
|
|
@ -354,6 +354,11 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #6629: Fix a data corruption issue in the new `io` package, 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 #4660: If a multiprocessing.JoinableQueue.put() was preempted, it was
|
- Issue #4660: If a multiprocessing.JoinableQueue.put() was preempted, it was
|
||||||
possible to get a spurious 'task_done() called too many times' error.
|
possible to get a spurious 'task_done() called too many times' error.
|
||||||
|
|
||||||
|
|
|
@ -1774,6 +1774,19 @@ bufferedwriter_write(buffered *self, PyObject *args)
|
||||||
}
|
}
|
||||||
Py_CLEAR(res);
|
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. */
|
/* Then write buf itself. At this point the buffer has been emptied. */
|
||||||
remaining = buf.len;
|
remaining = buf.len;
|
||||||
written = 0;
|
written = 0;
|
||||||
|
|
Loading…
Reference in New Issue