Skip to content

Commit cc13016

Browse files
bpo-34068: _io__IOBase_close_impl could call _PyObject_SetAttrId with an exception set (GH-8282). (GH-8312)
(cherry picked from commit 28f0736) Co-authored-by: Zackery Spytz <[email protected]>
1 parent 8b5d191 commit cc13016

File tree

3 files changed

+20
-4
lines changed

3 files changed

+20
-4
lines changed

Lib/test/test_io.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,16 @@ def read1(self, size):
957957
self.assertSequenceEqual(buffer[result:], unused)
958958
self.assertEqual(len(reader.avail), avail - result)
959959

960+
def test_close_assert(self):
961+
class R(self.IOBase):
962+
def __setattr__(self, name, value):
963+
pass
964+
def flush(self):
965+
raise OSError()
966+
f = R()
967+
# This would cause an assertion failure.
968+
self.assertRaises(OSError, f.close)
969+
960970

961971
class CIOTest(IOTest):
962972

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
In :meth:`io.IOBase.close`, ensure that the :attr:`~io.IOBase.closed`
2+
attribute is not set with a live exception. Patch by Zackery Spytz and Serhiy
3+
Storchaka.

Modules/_io/iobase.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -210,16 +210,19 @@ static PyObject *
210210
_io__IOBase_close_impl(PyObject *self)
211211
/*[clinic end generated code: output=63c6a6f57d783d6d input=f4494d5c31dbc6b7]*/
212212
{
213-
PyObject *res;
213+
PyObject *res, *exc, *val, *tb;
214+
int rc;
214215

215216
if (IS_CLOSED(self))
216217
Py_RETURN_NONE;
217218

218219
res = PyObject_CallMethodObjArgs(self, _PyIO_str_flush, NULL);
219220

220-
if (_PyObject_SetAttrId(self, &PyId___IOBase_closed, Py_True) < 0) {
221-
Py_XDECREF(res);
222-
return NULL;
221+
PyErr_Fetch(&exc, &val, &tb);
222+
rc = _PyObject_SetAttrId(self, &PyId___IOBase_closed, Py_True);
223+
_PyErr_ChainExceptions(exc, val, tb);
224+
if (rc < 0) {
225+
Py_CLEAR(res);
223226
}
224227

225228
if (res == NULL)

0 commit comments

Comments
 (0)