mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
gh-140650: Fix write(), flush() and close() methods of io.BufferedWriter (GH-140653)
They could raise SystemError or crash when getting the "closed" attribute or converting it to boolean raises an exception.
This commit is contained in:
parent
3cb1ab0e5d
commit
1d25b751c5
3 changed files with 43 additions and 6 deletions
|
|
@ -962,6 +962,27 @@ def test_args_error(self):
|
||||||
with self.assertRaisesRegex(TypeError, "BufferedWriter"):
|
with self.assertRaisesRegex(TypeError, "BufferedWriter"):
|
||||||
self.tp(self.BytesIO(), 1024, 1024, 1024)
|
self.tp(self.BytesIO(), 1024, 1024, 1024)
|
||||||
|
|
||||||
|
def test_non_boolean_closed_attr(self):
|
||||||
|
# gh-140650: check TypeError is raised
|
||||||
|
class MockRawIOWithoutClosed(self.MockRawIO):
|
||||||
|
closed = NotImplemented
|
||||||
|
|
||||||
|
bufio = self.tp(MockRawIOWithoutClosed())
|
||||||
|
self.assertRaises(TypeError, bufio.write, b"")
|
||||||
|
self.assertRaises(TypeError, bufio.flush)
|
||||||
|
self.assertRaises(TypeError, bufio.close)
|
||||||
|
|
||||||
|
def test_closed_attr_raises(self):
|
||||||
|
class MockRawIOClosedRaises(self.MockRawIO):
|
||||||
|
@property
|
||||||
|
def closed(self):
|
||||||
|
raise ValueError("test")
|
||||||
|
|
||||||
|
bufio = self.tp(MockRawIOClosedRaises())
|
||||||
|
self.assertRaisesRegex(ValueError, "test", bufio.write, b"")
|
||||||
|
self.assertRaisesRegex(ValueError, "test", bufio.flush)
|
||||||
|
self.assertRaisesRegex(ValueError, "test", bufio.close)
|
||||||
|
|
||||||
|
|
||||||
class PyBufferedWriterTest(BufferedWriterTest, PyTestCase):
|
class PyBufferedWriterTest(BufferedWriterTest, PyTestCase):
|
||||||
tp = pyio.BufferedWriter
|
tp = pyio.BufferedWriter
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
Fix an issue where closing :class:`io.BufferedWriter` could crash if
|
||||||
|
the closed attribute raised an exception on access or could not be
|
||||||
|
converted to a boolean.
|
||||||
|
|
@ -362,16 +362,24 @@ _enter_buffered_busy(buffered *self)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define IS_CLOSED(self) \
|
#define IS_CLOSED(self) \
|
||||||
(!self->buffer || \
|
(!self->buffer ? 1 : \
|
||||||
(self->fast_closed_checks \
|
(self->fast_closed_checks \
|
||||||
? _PyFileIO_closed(self->raw) \
|
? _PyFileIO_closed(self->raw) \
|
||||||
: buffered_closed(self)))
|
: buffered_closed(self)))
|
||||||
|
|
||||||
#define CHECK_CLOSED(self, error_msg) \
|
#define CHECK_CLOSED(self, error_msg) \
|
||||||
if (IS_CLOSED(self) && (Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t) == 0)) { \
|
do { \
|
||||||
PyErr_SetString(PyExc_ValueError, error_msg); \
|
int _closed = IS_CLOSED(self); \
|
||||||
return NULL; \
|
if (_closed < 0) { \
|
||||||
} \
|
return NULL; \
|
||||||
|
} \
|
||||||
|
if (_closed && \
|
||||||
|
(Py_SAFE_DOWNCAST(READAHEAD(self), Py_off_t, Py_ssize_t) == 0)) \
|
||||||
|
{ \
|
||||||
|
PyErr_SetString(PyExc_ValueError, error_msg); \
|
||||||
|
return NULL; \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
#define VALID_READ_BUFFER(self) \
|
#define VALID_READ_BUFFER(self) \
|
||||||
(self->readable && self->read_end != -1)
|
(self->readable && self->read_end != -1)
|
||||||
|
|
@ -2079,6 +2087,7 @@ _io_BufferedWriter_write_impl(buffered *self, Py_buffer *buffer)
|
||||||
PyObject *res = NULL;
|
PyObject *res = NULL;
|
||||||
Py_ssize_t written, avail, remaining;
|
Py_ssize_t written, avail, remaining;
|
||||||
Py_off_t offset;
|
Py_off_t offset;
|
||||||
|
int r;
|
||||||
|
|
||||||
CHECK_INITIALIZED(self)
|
CHECK_INITIALIZED(self)
|
||||||
|
|
||||||
|
|
@ -2087,7 +2096,11 @@ _io_BufferedWriter_write_impl(buffered *self, Py_buffer *buffer)
|
||||||
|
|
||||||
/* Issue #31976: Check for closed file after acquiring the lock. Another
|
/* Issue #31976: Check for closed file after acquiring the lock. Another
|
||||||
thread could be holding the lock while closing the file. */
|
thread could be holding the lock while closing the file. */
|
||||||
if (IS_CLOSED(self)) {
|
r = IS_CLOSED(self);
|
||||||
|
if (r < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (r > 0) {
|
||||||
PyErr_SetString(PyExc_ValueError, "write to closed file");
|
PyErr_SetString(PyExc_ValueError, "write to closed file");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue