mirror of https://github.com/python/cpython
GH-97592: Fix crash in C remove_done_callback due to evil code (#97660)
Evil code could cause fut_callbacks to be cleared when PyObject_RichCompareBool is called.
This commit is contained in:
parent
e9d63760fe
commit
63780f4599
|
@ -837,6 +837,21 @@ class BaseFutureDoneCallbackTests():
|
|||
|
||||
fut.remove_done_callback(evil())
|
||||
|
||||
def test_remove_done_callbacks_list_clear(self):
|
||||
# see https://github.com/python/cpython/issues/97592 for details
|
||||
|
||||
fut = self._new_future()
|
||||
fut.add_done_callback(str)
|
||||
|
||||
for _ in range(63):
|
||||
fut.add_done_callback(id)
|
||||
|
||||
class evil:
|
||||
def __eq__(self, other):
|
||||
fut.remove_done_callback(other)
|
||||
|
||||
fut.remove_done_callback(evil())
|
||||
|
||||
def test_schedule_callbacks_list_mutation_1(self):
|
||||
# see http://bugs.python.org/issue28963 for details
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Avoid a crash in the C version of :meth:`asyncio.Future.remove_done_callback` when an evil argument is passed.
|
|
@ -1052,7 +1052,11 @@ _asyncio_Future_remove_done_callback(FutureObj *self, PyObject *fn)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < PyList_GET_SIZE(self->fut_callbacks); i++) {
|
||||
// Beware: PyObject_RichCompareBool below may change fut_callbacks.
|
||||
// See GH-97592.
|
||||
for (i = 0;
|
||||
self->fut_callbacks != NULL && i < PyList_GET_SIZE(self->fut_callbacks);
|
||||
i++) {
|
||||
int ret;
|
||||
PyObject *item = PyList_GET_ITEM(self->fut_callbacks, i);
|
||||
Py_INCREF(item);
|
||||
|
@ -1071,7 +1075,8 @@ _asyncio_Future_remove_done_callback(FutureObj *self, PyObject *fn)
|
|||
}
|
||||
}
|
||||
|
||||
if (j == 0) {
|
||||
// Note: fut_callbacks may have been cleared.
|
||||
if (j == 0 || self->fut_callbacks == NULL) {
|
||||
Py_CLEAR(self->fut_callbacks);
|
||||
Py_DECREF(newlist);
|
||||
return PyLong_FromSsize_t(len + cleared_callback0);
|
||||
|
|
Loading…
Reference in New Issue