Skip to content

Commit

Permalink
bpo-46025: Fix a crash in the atexit module for auto-unregistering fu…
Browse files Browse the repository at this point in the history
…nctions (GH-30002) (GH-30005)

(cherry picked from commit f0d290d)

Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>

Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>
  • Loading branch information
miss-islington and pablogsal committed Dec 9, 2021
1 parent 2c2ee83 commit 934a24c
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 1 deletion.
15 changes: 15 additions & 0 deletions Lib/test/_test_atexit.py
Expand Up @@ -116,6 +116,21 @@ def test_bound_methods(self):
atexit._run_exitfuncs()
self.assertEqual(l, [5])

def test_atexit_with_unregistered_function(self):
# See bpo-46025 for more info
def func():
atexit.unregister(func)
1/0
atexit.register(func)
try:
with support.catch_unraisable_exception() as cm:
atexit._run_exitfuncs()
self.assertEqual(cm.unraisable.object, func)
self.assertEqual(cm.unraisable.exc_type, ZeroDivisionError)
self.assertEqual(type(cm.unraisable.exc_value), ZeroDivisionError)
finally:
atexit.unregister(func)


if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,2 @@
Fix a crash in the :mod:`atexit` module involving functions that unregister
themselves before raising exceptions. Patch by Pablo Galindo.
5 changes: 4 additions & 1 deletion Modules/atexitmodule.c
Expand Up @@ -93,13 +93,16 @@ atexit_callfuncs(struct atexit_state *state)
continue;
}

// bpo-46025: Increment the refcount of cb->func as the call itself may unregister it
PyObject* the_func = Py_NewRef(cb->func);
PyObject *res = PyObject_Call(cb->func, cb->args, cb->kwargs);
if (res == NULL) {
_PyErr_WriteUnraisableMsg("in atexit callback", cb->func);
_PyErr_WriteUnraisableMsg("in atexit callback", the_func);
}
else {
Py_DECREF(res);
}
Py_DECREF(the_func);
}

atexit_cleanup(state);
Expand Down

0 comments on commit 934a24c

Please sign in to comment.