From d879d3b108515aeb584103034a7442d1d1e7afbe Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 8 Jan 2026 12:59:03 +0100 Subject: [PATCH 1/4] gh-143547: Fix PyErr_FormatUnraisable() fallback Hold a strong reference to 'hook' while calling the default unraisable took to log hook failure. Fix test_sys.UnraisableHookTest: use the right decorator function to disable colors. Previously, tests were always skipped. --- Lib/test/test_sys.py | 3 ++- Python/errors.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 04018e9603ff13..1d8e908efb0572 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1350,7 +1350,7 @@ def test_disable_gil_abi(self): @test.support.cpython_only -@force_not_colorized +@test.support.force_not_colorized_test_class class UnraisableHookTest(unittest.TestCase): def test_original_unraisablehook(self): _testcapi = import_helper.import_module('_testcapi') @@ -1492,6 +1492,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/Python/errors.c b/Python/errors.c index 5c6ac48371a0ff..bab7793efe6332 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1692,6 +1692,7 @@ format_unraisable_v(const char *format, va_list va, PyObject *obj) } } + PyObject *hook = NULL; PyObject *hook_args = make_unraisable_hook_args( tstate, exc_type, exc_value, exc_tb, err_msg, obj); if (hook_args == NULL) { @@ -1700,7 +1701,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; @@ -1727,7 +1727,6 @@ format_unraisable_v(const char *format, va_list va, PyObject *obj) } PyObject *res = PyObject_CallOneArg(hook, hook_args); - Py_DECREF(hook); Py_DECREF(hook_args); if (res != NULL) { Py_DECREF(res); @@ -1757,6 +1756,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 */ } From d958a75d228fd74f6c896105299cba6a0e5146c7 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 8 Jan 2026 14:24:02 +0100 Subject: [PATCH 2/4] Fix clang compiler warning --- Python/errors.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/errors.c b/Python/errors.c index bab7793efe6332..841c023942c5ae 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1656,6 +1656,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); @@ -1692,7 +1693,6 @@ format_unraisable_v(const char *format, va_list va, PyObject *obj) } } - PyObject *hook = NULL; PyObject *hook_args = make_unraisable_hook_args( tstate, exc_type, exc_value, exc_tb, err_msg, obj); if (hook_args == NULL) { From 00c0c3b6866abce48b0d7ad6c05b772d93d6c213 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 8 Jan 2026 14:53:48 +0100 Subject: [PATCH 3/4] Add NEWS entry --- .../Library/2026-01-08-14-53-46.gh-issue-143547.wHBVlr.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-01-08-14-53-46.gh-issue-143547.wHBVlr.rst 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. From 50b2a9046cc8788b11c1a9cf2f8de25a0b7b414c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Jan 2026 12:35:42 +0100 Subject: [PATCH 4/4] Fix ref counting --- Python/errors.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Python/errors.c b/Python/errors.c index 841c023942c5ae..229e3a565db5cf 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1713,7 +1713,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; @@ -1721,7 +1720,6 @@ 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; }