]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-143547: Fix PyErr_FormatUnraisable() fallback (#143557)
authorVictor Stinner <vstinner@python.org>
Fri, 9 Jan 2026 12:16:22 +0000 (13:16 +0100)
committerGitHub <noreply@github.com>
Fri, 9 Jan 2026 12:16:22 +0000 (13:16 +0100)
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
Misc/NEWS.d/next/Library/2026-01-08-14-53-46.gh-issue-143547.wHBVlr.rst [new file with mode: 0644]
Python/errors.c

index 04018e9603ff135ff7310fa009dc7ae5ede8dda2..1d8e908efb057269833acaac427cfe1c2d147634 100644 (file)
@@ -1350,7 +1350,7 @@ class SysModuleTest(unittest.TestCase):
 
 
 @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 @@ class UnraisableHookTest(unittest.TestCase):
     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 (file)
index 0000000..934570b
--- /dev/null
@@ -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.
index 5c6ac48371a0ff133579922c226f32242a915448..229e3a565db5cf0197aed8aa3c465fc72eca57f9 100644 (file)
@@ -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);
 
@@ -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;
@@ -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,13 +1720,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);
@@ -1757,6 +1754,7 @@ done:
     Py_XDECREF(exc_value);
     Py_XDECREF(exc_tb);
     Py_XDECREF(err_msg);
+    Py_XDECREF(hook);
     _PyErr_Clear(tstate); /* Just in case */
 }