Skip to content

Commit e275587

Browse files
author
antoine.pitrou
committed
Merged revisions 74338 via svnmerge from
svn+ssh://[email protected]/python/branches/py3k ................ r74338 | antoine.pitrou | 2009-08-06 22:29:56 +0200 (jeu., 06 août 2009) | 14 lines Merged revisions 74336 via svnmerge from svn+ssh://[email protected]/python/trunk ........ r74336 | antoine.pitrou | 2009-08-06 22:18:29 +0200 (jeu., 06 août 2009) | 8 lines 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. ........ ................ git-svn-id: http://svn.python.org/projects/python/branches/release31-maint@74339 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 95f77f5 commit e275587

3 files changed

Lines changed: 38 additions & 0 deletions

File tree

Lib/test/test_io.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,6 +1328,26 @@ def _read(bufio):
13281328
bufio.readinto(bytearray(1))
13291329
self.check_writes(_read)
13301330

1331+
def test_write_after_readahead(self):
1332+
# Issue #6629: writing after the buffer was filled by readahead should
1333+
# first rewind the raw stream.
1334+
for overwrite_size in [1, 5]:
1335+
raw = self.BytesIO(b"A" * 10)
1336+
bufio = self.tp(raw, 4)
1337+
# Trigger readahead
1338+
self.assertEqual(bufio.read(1), b"A")
1339+
self.assertEqual(bufio.tell(), 1)
1340+
# Overwriting should rewind the raw stream if it needs so
1341+
bufio.write(b"B" * overwrite_size)
1342+
self.assertEqual(bufio.tell(), overwrite_size + 1)
1343+
# If the write size was smaller than the buffer size, flush() and
1344+
# check that rewind happens.
1345+
bufio.flush()
1346+
self.assertEqual(bufio.tell(), overwrite_size + 1)
1347+
s = raw.getvalue()
1348+
self.assertEqual(s,
1349+
b"A" + b"B" * overwrite_size + b"A" * (9 - overwrite_size))
1350+
13311351
def test_misbehaved_io(self):
13321352
BufferedReaderTest.test_misbehaved_io(self)
13331353
BufferedWriterTest.test_misbehaved_io(self)

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ C-API
4242
Library
4343
-------
4444

45+
- Issue #6629: Fix a data corruption issue in the new I/O library, which could
46+
occur when writing to a BufferedRandom object (e.g. a file opened in "rb+" or
47+
"wb+" mode) after having buffered a certain amount of data for reading. This
48+
bug was not present in the pure Python implementation.
49+
4550
- Issue #6622: Fix "local variable 'secret' referenced before
4651
assignment" bug in POP3.apop.
4752

Modules/_io/bufferedio.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1757,6 +1757,19 @@ bufferedwriter_write(buffered *self, PyObject *args)
17571757
}
17581758
Py_CLEAR(res);
17591759

1760+
/* Adjust the raw stream position if it is away from the logical stream
1761+
position. This happens if the read buffer has been filled but not
1762+
modified (and therefore _bufferedwriter_flush_unlocked() didn't rewind
1763+
the raw stream by itself).
1764+
Fixes issue #6629.
1765+
*/
1766+
n = RAW_OFFSET(self);
1767+
if (n != 0) {
1768+
if (_buffered_raw_seek(self, -n, 1) < 0)
1769+
goto error;
1770+
self->raw_pos -= n;
1771+
}
1772+
17601773
/* Then write buf itself. At this point the buffer has been emptied. */
17611774
remaining = buf.len;
17621775
written = 0;

0 commit comments

Comments
 (0)