finally:
atexit.unregister(func)
+ def test_eq_unregister_clear(self):
+ # Issue #112127: callback's __eq__ may call unregister or _clear
+ class Evil:
+ def __eq__(self, other):
+ action(other)
+ return NotImplemented
+
+ for action in atexit.unregister, lambda o: atexit._clear():
+ with self.subTest(action=action):
+ atexit.register(lambda: None)
+ atexit.unregister(Evil())
+ atexit._clear()
+
if __name__ == "__main__":
unittest.main()
atexit_unregister_locked(PyObject *callbacks, PyObject *func)
{
for (Py_ssize_t i = 0; i < PyList_GET_SIZE(callbacks); ++i) {
- PyObject *tuple = PyList_GET_ITEM(callbacks, i);
+ PyObject *tuple = Py_NewRef(PyList_GET_ITEM(callbacks, i));
assert(PyTuple_CheckExact(tuple));
PyObject *to_compare = PyTuple_GET_ITEM(tuple, 0);
int cmp = PyObject_RichCompareBool(func, to_compare, Py_EQ);
+ Py_DECREF(tuple);
if (cmp < 0)
{
return -1;