Skip to content

Commit 4e22157

Browse files
committed
bpo-35950: Raise OSError in io.BufferedReader.truncate()
The truncate() method of io.BufferedReader() should raise OSError when it is called on a read-only io.BufferedReader() instance.
1 parent 2a58b06 commit 4e22157

File tree

3 files changed

+26
-5
lines changed

3 files changed

+26
-5
lines changed

Lib/_pyio.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,10 @@ def tell(self):
792792
return pos
793793

794794
def truncate(self, pos=None):
795+
if self.closed:
796+
raise ValueError("truncate on closed file")
797+
if not self.writable():
798+
raise OSError("truncate on read-only reader")
795799
# Flush the stream. We're mixing buffered I/O with lower-level I/O,
796800
# and a flush may be necessary to synch both views of the current
797801
# file state.

Lib/test/test_io.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,6 +1514,13 @@ def test_read_on_closed(self):
15141514
self.assertRaises(ValueError, b.peek)
15151515
self.assertRaises(ValueError, b.read1, 1)
15161516

1517+
def test_truncate_on_read_only(self):
1518+
rawio = self.MockFileIO(b"abc")
1519+
bufio = self.tp(rawio)
1520+
self.assertFalse(bufio.writable())
1521+
self.assertRaises(OSError, bufio.truncate)
1522+
self.assertRaises(OSError, bufio.truncate, 0)
1523+
15171524

15181525
class CBufferedReaderTest(BufferedReaderTest, SizeofTest):
15191526
tp = io.BufferedReader
@@ -2346,6 +2353,10 @@ def test_interleaved_readline_write(self):
23462353
# You can't construct a BufferedRandom over a non-seekable stream.
23472354
test_unseekable = None
23482355

2356+
# writable() returns True, so there's no point to test it over
2357+
# a writable stream.
2358+
test_truncate_on_read_only = None
2359+
23492360

23502361
class CBufferedRandomTest(BufferedRandomTest, SizeofTest):
23512362
tp = io.BufferedRandom

Modules/_io/bufferedio.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,15 +1314,21 @@ _io__Buffered_truncate_impl(buffered *self, PyObject *pos)
13141314
PyObject *res = NULL;
13151315

13161316
CHECK_INITIALIZED(self)
1317+
CHECK_CLOSED(self, "truncate of closed file")
13171318
if (!ENTER_BUFFERED(self))
13181319
return NULL;
1320+
if (!self->writable) {
1321+
LEAVE_BUFFERED(self)
1322+
PyErr_SetString(PyExc_OSError, "truncate on read-only reader");
1323+
return NULL;
1324+
}
13191325

1320-
if (self->writable) {
1321-
res = buffered_flush_and_rewind_unlocked(self);
1322-
if (res == NULL)
1323-
goto end;
1324-
Py_CLEAR(res);
1326+
res = buffered_flush_and_rewind_unlocked(self);
1327+
if (res == NULL) {
1328+
goto end;
13251329
}
1330+
Py_CLEAR(res);
1331+
13261332
res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_truncate, pos, NULL);
13271333
if (res == NULL)
13281334
goto end;

0 commit comments

Comments
 (0)