Skip to content

Commit fc153d1

Browse files
[2.7] bpo-34068: iobase_close could call PyObject_SetAttrString with an exception set (GH-8282). (GH-8312) (GH-8314)
(cherry picked from commit 28f0736) Co-authored-by: Zackery Spytz <[email protected]>. (cherry picked from commit cc13016)
1 parent a45fa39 commit fc153d1

File tree

3 files changed

+24
-3
lines changed

3 files changed

+24
-3
lines changed

Lib/test/test_io.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,16 @@ def read(self, size):
690690
self.assertEqual(stream.readinto(buffer), 5)
691691
self.assertEqual(buffer.tobytes(), b"12345")
692692

693+
def test_close_assert(self):
694+
class R(self.IOBase):
695+
def __setattr__(self, name, value):
696+
pass
697+
def flush(self):
698+
raise OSError()
699+
f = R()
700+
# This would cause an assertion failure.
701+
self.assertRaises(OSError, f.close)
702+
693703

694704
class CIOTest(IOTest):
695705

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: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,17 +177,25 @@ _PyIOBase_check_closed(PyObject *self, PyObject *args)
177177
static PyObject *
178178
iobase_close(PyObject *self, PyObject *args)
179179
{
180-
PyObject *res;
180+
PyObject *res, *exc, *val, *tb;
181+
int rc;
181182

182183
if (IS_CLOSED(self))
183184
Py_RETURN_NONE;
184185

185186
res = PyObject_CallMethodObjArgs(self, _PyIO_str_flush, NULL);
186-
PyObject_SetAttrString(self, "__IOBase_closed", Py_True);
187+
188+
PyErr_Fetch(&exc, &val, &tb);
189+
rc = PyObject_SetAttrString(self, "__IOBase_closed", Py_True);
190+
_PyErr_ReplaceException(exc, val, tb);
191+
if (rc < 0) {
192+
Py_CLEAR(res);
193+
}
194+
187195
if (res == NULL) {
188196
return NULL;
189197
}
190-
Py_XDECREF(res);
198+
Py_DECREF(res);
191199
Py_RETURN_NONE;
192200
}
193201

0 commit comments

Comments
 (0)