Skip to content

gh-98999: Raise ValueError in _pyio on closed buffers #99009

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Lib/_pyio.py
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,7 @@ def peek(self, size=0):
do at most one raw read to satisfy it. We never return more
than self.buffer_size.
"""
self._checkClosed("peek of closed file")
with self._read_lock:
return self._peek_unlocked(size)

Expand All @@ -1147,6 +1148,7 @@ def read1(self, size=-1):
"""Reads up to size bytes, with at most one read() system call."""
# Returns up to size bytes. If at least one byte is buffered, we
# only return buffered bytes. Otherwise, we do one raw read.
self._checkClosed("read of closed file")
if size < 0:
size = self.buffer_size
if size == 0:
Expand All @@ -1164,6 +1166,8 @@ def read1(self, size=-1):
def _readinto(self, buf, read1):
"""Read data into *buf* with at most one system call."""

self._checkClosed("readinto of closed file")

# Need to create a memoryview object of type 'b', otherwise
# we may not be able to assign bytes to it, and slicing it
# would create a new object.
Expand Down Expand Up @@ -1213,6 +1217,7 @@ def tell(self):
def seek(self, pos, whence=0):
if whence not in valid_seek_flags:
raise ValueError("invalid whence value")
self._checkClosed("seek of closed file")
with self._read_lock:
if whence == 1:
pos -= len(self._read_buf) - self._read_pos
Expand Down
38 changes: 26 additions & 12 deletions Lib/test/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -1531,11 +1531,25 @@ def test_no_extraneous_read(self):

def test_read_on_closed(self):
# Issue #23796
b = io.BufferedReader(io.BytesIO(b"12"))
b = self.BufferedReader(self.BytesIO(b"12"))
b.read(1)
b.close()
self.assertRaises(ValueError, b.peek)
self.assertRaises(ValueError, b.read1, 1)
with self.subTest('peek'):
self.assertRaises(ValueError, b.peek)
with self.subTest('read1'):
self.assertRaises(ValueError, b.read1, 1)
with self.subTest('read'):
self.assertRaises(ValueError, b.read)
with self.subTest('readinto'):
self.assertRaises(ValueError, b.readinto, bytearray())
with self.subTest('readinto1'):
self.assertRaises(ValueError, b.readinto1, bytearray())
with self.subTest('flush'):
self.assertRaises(ValueError, b.flush)
with self.subTest('truncate'):
self.assertRaises(ValueError, b.truncate)
with self.subTest('seek'):
self.assertRaises(ValueError, b.seek, 0)

def test_truncate_on_read_only(self):
rawio = self.MockFileIO(b"abc")
Expand Down Expand Up @@ -1593,18 +1607,18 @@ def test_garbage_collection(self):
def test_args_error(self):
# Issue #17275
with self.assertRaisesRegex(TypeError, "BufferedReader"):
self.tp(io.BytesIO(), 1024, 1024, 1024)
self.tp(self.BytesIO(), 1024, 1024, 1024)

def test_bad_readinto_value(self):
rawio = io.BufferedReader(io.BytesIO(b"12"))
rawio = self.tp(self.BytesIO(b"12"))
rawio.readinto = lambda buf: -1
bufio = self.tp(rawio)
with self.assertRaises(OSError) as cm:
bufio.readline()
self.assertIsNone(cm.exception.__cause__)

def test_bad_readinto_type(self):
rawio = io.BufferedReader(io.BytesIO(b"12"))
rawio = self.tp(self.BytesIO(b"12"))
rawio.readinto = lambda buf: b''
bufio = self.tp(rawio)
with self.assertRaises(OSError) as cm:
Expand Down Expand Up @@ -1747,7 +1761,7 @@ def test_write_non_blocking(self):
self.assertTrue(s.startswith(b"01234567A"), s)

def test_write_and_rewind(self):
raw = io.BytesIO()
raw = self.BytesIO()
bufio = self.tp(raw, 4)
self.assertEqual(bufio.write(b"abcdef"), 6)
self.assertEqual(bufio.tell(), 6)
Expand Down Expand Up @@ -1957,7 +1971,7 @@ def test_garbage_collection(self):
def test_args_error(self):
# Issue #17275
with self.assertRaisesRegex(TypeError, "BufferedWriter"):
self.tp(io.BytesIO(), 1024, 1024, 1024)
self.tp(self.BytesIO(), 1024, 1024, 1024)


class PyBufferedWriterTest(BufferedWriterTest):
Expand Down Expand Up @@ -2433,7 +2447,7 @@ def test_garbage_collection(self):
def test_args_error(self):
# Issue #17275
with self.assertRaisesRegex(TypeError, "BufferedRandom"):
self.tp(io.BytesIO(), 1024, 1024, 1024)
self.tp(self.BytesIO(), 1024, 1024, 1024)


class PyBufferedRandomTest(BufferedRandomTest):
Expand Down Expand Up @@ -3465,7 +3479,7 @@ def test_illegal_encoder(self):
# encode() is invalid shouldn't cause an assertion failure.
rot13 = codecs.lookup("rot13")
with support.swap_attr(rot13, '_is_text_encoding', True):
t = io.TextIOWrapper(io.BytesIO(b'foo'), encoding="rot13")
t = self.TextIOWrapper(self.BytesIO(b'foo'), encoding="rot13")
self.assertRaises(TypeError, t.write, 'bar')

def test_illegal_decoder(self):
Expand Down Expand Up @@ -3571,7 +3585,7 @@ def seekable(self): return True
t = self.TextIOWrapper(F(), encoding='utf-8')

def test_reconfigure_locale(self):
wrapper = io.TextIOWrapper(io.BytesIO(b"test"))
wrapper = self.TextIOWrapper(self.BytesIO(b"test"))
wrapper.reconfigure(encoding="locale")

def test_reconfigure_encoding_read(self):
Expand Down Expand Up @@ -3741,7 +3755,7 @@ def test_garbage_collection(self):
# all data to disk.
# The Python version has __del__, so it ends in gc.garbage instead.
with warnings_helper.check_warnings(('', ResourceWarning)):
rawio = io.FileIO(os_helper.TESTFN, "wb")
rawio = self.FileIO(os_helper.TESTFN, "wb")
b = self.BufferedWriter(rawio)
t = self.TextIOWrapper(b, encoding="ascii")
t.write("456def")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Now :mod:`_pyio` is consistent with :mod:`_io` in raising ``ValueError``
when executing methods over closed buffers.