]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-35950: Raise UnsupportedOperation in BufferedReader.truncate() (GH-18586)
authorBerker Peksag <berker.peksag@gmail.com>
Fri, 21 Feb 2020 17:57:26 +0000 (20:57 +0300)
committerGitHub <noreply@github.com>
Fri, 21 Feb 2020 17:57:26 +0000 (09:57 -0800)
The truncate() method of io.BufferedReader() should raise
UnsupportedOperation when it is called on a read-only
io.BufferedReader() instance.

https://bugs.python.org/issue35950

Automerge-Triggered-By: @methane
Lib/_pyio.py
Lib/test/test_io.py
Misc/NEWS.d/next/Library/2020-02-21-02-42-41.bpo-35950.9G3-wl.rst [new file with mode: 0644]
Modules/_io/bufferedio.c

index 4c2414672ed56c154cbab2a7432a7f663ef1ce2d..8eaa114c07c916a4ebe0de63828256fe9a8b5dd6 100644 (file)
@@ -792,6 +792,9 @@ class _BufferedIOMixin(BufferedIOBase):
         return pos
 
     def truncate(self, pos=None):
+        self._checkClosed()
+        self._checkWritable()
+
         # Flush the stream.  We're mixing buffered I/O with lower-level I/O,
         # and a flush may be necessary to synch both views of the current
         # file state.
index 0bfa4d249e9a6bfcfec8303d2b53f2d60a7d8a92..c27dfd96bc00dd3aff086c65f044d7703a6c29ab 100644 (file)
@@ -1528,6 +1528,13 @@ class BufferedReaderTest(unittest.TestCase, CommonBufferedTests):
         self.assertRaises(ValueError, b.peek)
         self.assertRaises(ValueError, b.read1, 1)
 
+    def test_truncate_on_read_only(self):
+        rawio = self.MockFileIO(b"abc")
+        bufio = self.tp(rawio)
+        self.assertFalse(bufio.writable())
+        self.assertRaises(self.UnsupportedOperation, bufio.truncate)
+        self.assertRaises(self.UnsupportedOperation, bufio.truncate, 0)
+
 
 class CBufferedReaderTest(BufferedReaderTest, SizeofTest):
     tp = io.BufferedReader
@@ -2372,6 +2379,10 @@ class BufferedRandomTest(BufferedReaderTest, BufferedWriterTest):
     # You can't construct a BufferedRandom over a non-seekable stream.
     test_unseekable = None
 
+    # writable() returns True, so there's no point to test it over
+    # a writable stream.
+    test_truncate_on_read_only = None
+
 
 class CBufferedRandomTest(BufferedRandomTest, SizeofTest):
     tp = io.BufferedRandom
diff --git a/Misc/NEWS.d/next/Library/2020-02-21-02-42-41.bpo-35950.9G3-wl.rst b/Misc/NEWS.d/next/Library/2020-02-21-02-42-41.bpo-35950.9G3-wl.rst
new file mode 100644 (file)
index 0000000..92e3b23
--- /dev/null
@@ -0,0 +1,2 @@
+Raise :exc:`io.UnsupportedOperation` in :meth:`io.BufferedReader.truncate`
+when it is called on a read-only :class:`io.BufferedReader` instance.
index 6f55577813c9fb5e6eaee5ead1696d21e64bf215..a09082c84f8a210c903f12f988f69983dc87d8da 100644 (file)
@@ -1315,15 +1315,19 @@ _io__Buffered_truncate_impl(buffered *self, PyObject *pos)
     PyObject *res = NULL;
 
     CHECK_INITIALIZED(self)
+    CHECK_CLOSED(self, "truncate of closed file")
+    if (!self->writable) {
+        return bufferediobase_unsupported("truncate");
+    }
     if (!ENTER_BUFFERED(self))
         return NULL;
 
-    if (self->writable) {
-        res = buffered_flush_and_rewind_unlocked(self);
-        if (res == NULL)
-            goto end;
-        Py_CLEAR(res);
+    res = buffered_flush_and_rewind_unlocked(self);
+    if (res == NULL) {
+        goto end;
     }
+    Py_CLEAR(res);
+
     res = PyObject_CallMethodOneArg(self->raw, _PyIO_str_truncate, pos);
     if (res == NULL)
         goto end;