]> granicus.if.org Git - python/commitdiff
Merged revisions 74338 via svnmerge from
authorAntoine Pitrou <solipsis@pitrou.net>
Thu, 6 Aug 2009 20:52:43 +0000 (20:52 +0000)
committerAntoine Pitrou <solipsis@pitrou.net>
Thu, 6 Aug 2009 20:52:43 +0000 (20:52 +0000)
svn+ssh://pythondev@svn.python.org/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://pythondev@svn.python.org/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.
  ........
................

Lib/test/test_io.py
Misc/NEWS
Modules/_io/bufferedio.c

index 729c0ca7c19926076dff3c6ee78851342bebab15..407a8a4b66333e0c2b1b95c2369ae57d98d84b21 100644 (file)
@@ -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)
index 0de8ad58dafaa1832ce73ad49833404f39e760e6..582def6aa968e26e72c354026b9283032a1fd141 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -42,6 +42,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.
 
index 98f8413b31e4f6451699d94f08635e3e62364b3e..d8b6471fd7f03df4d8c9400ae3110f5e30d831ee 100644 (file)
@@ -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;