[Python-checkins] bpo-32228: Reset raw_pos after unwinding the raw stream (#4858)

Antoine Pitrou webhook-mailer at python.org
Sun Jan 28 11:00:12 EST 2018


https://github.com/python/cpython/commit/059f58ce938d9c3f0286412a4efb1b9131339421
commit: 059f58ce938d9c3f0286412a4efb1b9131339421
branch: master
author: Nitish Chandra <nitishchandrachinta at gmail.com>
committer: Antoine Pitrou <pitrou at free.fr>
date: 2018-01-28T17:00:09+01:00
summary:

bpo-32228: Reset raw_pos after unwinding the raw stream (#4858)

Ensure that ``truncate()`` preserves the file position (as reported by ``tell()``) after writes longer than the buffer size.

files:
A Misc/NEWS.d/next/Library/2017-12-22-16-47-41.bpo-32228.waPx3q.rst
M Lib/test/test_io.py
M Modules/_io/bufferedio.c

diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index c6345e9199ca..4be5631ab446 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -1723,6 +1723,23 @@ def test_truncate(self):
         with self.open(support.TESTFN, "rb", buffering=0) as f:
             self.assertEqual(f.read(), b"abc")
 
+    def test_truncate_after_write(self):
+        # Ensure that truncate preserves the file position after
+        # writes longer than the buffer size.
+        # Issue: https://bugs.python.org/issue32228
+        with self.open(support.TESTFN, "wb") as f:
+            # Fill with some buffer
+            f.write(b'\x00' * 10000)
+        buffer_sizes = [8192, 4096, 200]
+        for buffer_size in buffer_sizes:
+            with self.open(support.TESTFN, "r+b", buffering=buffer_size) as f:
+                f.write(b'\x00' * (buffer_size + 1))
+                # After write write_pos and write_end are set to 0
+                f.read(1)
+                # read operation makes sure that pos != raw_pos
+                f.truncate()
+                self.assertEqual(f.tell(), buffer_size + 2)
+
     @support.requires_resource('cpu')
     def test_threads(self):
         try:
diff --git a/Misc/NEWS.d/next/Library/2017-12-22-16-47-41.bpo-32228.waPx3q.rst b/Misc/NEWS.d/next/Library/2017-12-22-16-47-41.bpo-32228.waPx3q.rst
new file mode 100644
index 000000000000..3bbe7c495f82
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2017-12-22-16-47-41.bpo-32228.waPx3q.rst
@@ -0,0 +1 @@
+Ensure that ``truncate()`` preserves the file position (as reported by ``tell()``) after writes longer than the buffer size.
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index 2b7aaaf7c7d0..358a654a98ca 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -1292,7 +1292,6 @@ _io__Buffered_seek_impl(buffered *self, PyObject *targetobj, int whence)
         if (res == NULL)
             goto end;
         Py_CLEAR(res);
-        _bufferedwriter_reset_buf(self);
     }
 
     /* TODO: align on block boundary and read buffer if needed? */
@@ -1852,8 +1851,6 @@ _bufferedwriter_raw_write(buffered *self, char *start, Py_ssize_t len)
     return n;
 }
 
-/* `restore_pos` is 1 if we need to restore the raw stream position at
-   the end, 0 otherwise. */
 static PyObject *
 _bufferedwriter_flush_unlocked(buffered *self)
 {
@@ -1894,9 +1891,18 @@ _bufferedwriter_flush_unlocked(buffered *self)
             goto error;
     }
 
-    _bufferedwriter_reset_buf(self);
 
 end:
+    /* This ensures that after return from this function,
+       VALID_WRITE_BUFFER(self) returns false.
+
+       This is a required condition because when a tell() is called
+       after flushing and if VALID_READ_BUFFER(self) is false, we need
+       VALID_WRITE_BUFFER(self) to be false to have
+       RAW_OFFSET(self) == 0.
+
+       Issue: https://bugs.python.org/issue32228 */
+    _bufferedwriter_reset_buf(self);
     Py_RETURN_NONE;
 
 error:



More information about the Python-checkins mailing list