diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 6b37094ed5fc32..7b4901040ba0f1 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1495,6 +1495,7 @@ def hook_func(args): def test_custom_unraisablehook_fail(self): _testcapi = import_helper.import_module('_testcapi') from _testcapi import err_writeunraisable + def hook_func(*args): raise Exception("hook_func failed") diff --git a/Misc/NEWS.d/next/Library/2026-01-08-14-53-46.gh-issue-143547.wHBVlr.rst b/Misc/NEWS.d/next/Library/2026-01-08-14-53-46.gh-issue-143547.wHBVlr.rst new file mode 100644 index 00000000000000..934570b30b971f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-08-14-53-46.gh-issue-143547.wHBVlr.rst @@ -0,0 +1,3 @@ +Fix :func:`sys.unraisablehook` when the hook raises an exception and changes +:func:`sys.unraisablehook`: hold a strong reference to the old hook. Patch +by Victor Stinner. diff --git a/Python/errors.c b/Python/errors.c index bf5aacf6e8b62a..14eec305bb4a6a 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1593,6 +1593,7 @@ format_unraisable_v(const char *format, va_list va, PyObject *obj) _Py_EnsureTstateNotNULL(tstate); PyObject *err_msg = NULL; + PyObject *hook = NULL; PyObject *exc_type, *exc_value, *exc_tb; _PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb); @@ -1637,7 +1638,6 @@ format_unraisable_v(const char *format, va_list va, PyObject *obj) goto error; } - PyObject *hook; if (_PySys_GetOptionalAttr(&_Py_ID(unraisablehook), &hook) < 0) { Py_DECREF(hook_args); err_msg_str = NULL; @@ -1650,7 +1650,6 @@ format_unraisable_v(const char *format, va_list va, PyObject *obj) } if (_PySys_Audit(tstate, "sys.unraisablehook", "OO", hook, hook_args) < 0) { - Py_DECREF(hook); Py_DECREF(hook_args); err_msg_str = "Exception ignored in audit hook"; obj = NULL; @@ -1658,13 +1657,11 @@ format_unraisable_v(const char *format, va_list va, PyObject *obj) } if (hook == Py_None) { - Py_DECREF(hook); Py_DECREF(hook_args); goto default_hook; } PyObject *res = PyObject_CallOneArg(hook, hook_args); - Py_DECREF(hook); Py_DECREF(hook_args); if (res != NULL) { Py_DECREF(res); @@ -1694,6 +1691,7 @@ format_unraisable_v(const char *format, va_list va, PyObject *obj) Py_XDECREF(exc_value); Py_XDECREF(exc_tb); Py_XDECREF(err_msg); + Py_XDECREF(hook); _PyErr_Clear(tstate); /* Just in case */ }