Skip to content

Commit 059f58c

Browse files
nitishchpitrou
authored andcommitted
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.
1 parent 79db11c commit 059f58c

3 files changed

Lines changed: 28 additions & 4 deletions

File tree

‎Lib/test/test_io.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,6 +1723,23 @@ def test_truncate(self):
17231723
with self.open(support.TESTFN, "rb", buffering=0) as f:
17241724
self.assertEqual(f.read(), b"abc")
17251725

1726+
def test_truncate_after_write(self):
1727+
# Ensure that truncate preserves the file position after
1728+
# writes longer than the buffer size.
1729+
# Issue: https://bugs.python.org/issue32228
1730+
with self.open(support.TESTFN, "wb") as f:
1731+
# Fill with some buffer
1732+
f.write(b'\x00' * 10000)
1733+
buffer_sizes = [8192, 4096, 200]
1734+
for buffer_size in buffer_sizes:
1735+
with self.open(support.TESTFN, "r+b", buffering=buffer_size) as f:
1736+
f.write(b'\x00' * (buffer_size + 1))
1737+
# After write write_pos and write_end are set to 0
1738+
f.read(1)
1739+
# read operation makes sure that pos != raw_pos
1740+
f.truncate()
1741+
self.assertEqual(f.tell(), buffer_size + 2)
1742+
17261743
@support.requires_resource('cpu')
17271744
def test_threads(self):
17281745
try:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Ensure that ``truncate()`` preserves the file position (as reported by ``tell()``) after writes longer than the buffer size.

‎Modules/_io/bufferedio.c‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,7 +1292,6 @@ _io__Buffered_seek_impl(buffered *self, PyObject *targetobj, int whence)
12921292
if (res == NULL)
12931293
goto end;
12941294
Py_CLEAR(res);
1295-
_bufferedwriter_reset_buf(self);
12961295
}
12971296

12981297
/* 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)
18521851
return n;
18531852
}
18541853

1855-
/* `restore_pos` is 1 if we need to restore the raw stream position at
1856-
the end, 0 otherwise. */
18571854
static PyObject *
18581855
_bufferedwriter_flush_unlocked(buffered *self)
18591856
{
@@ -1894,9 +1891,18 @@ _bufferedwriter_flush_unlocked(buffered *self)
18941891
goto error;
18951892
}
18961893

1897-
_bufferedwriter_reset_buf(self);
18981894

18991895
end:
1896+
/* This ensures that after return from this function,
1897+
VALID_WRITE_BUFFER(self) returns false.
1898+
1899+
This is a required condition because when a tell() is called
1900+
after flushing and if VALID_READ_BUFFER(self) is false, we need
1901+
VALID_WRITE_BUFFER(self) to be false to have
1902+
RAW_OFFSET(self) == 0.
1903+
1904+
Issue: https://bugs.python.org/issue32228 */
1905+
_bufferedwriter_reset_buf(self);
19001906
Py_RETURN_NONE;
19011907

19021908
error:

0 commit comments

Comments
 (0)