https://github.com/python/cpython/commit/57c56b0fb173e4b39ef4591d8745049ede129034
commit: 57c56b0fb173e4b39ef4591d8745049ede129034
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: vstinner <[email protected]>
date: 2026-01-09T15:33:25Z
summary:

[3.13] gh-143547: Fix PyErr_FormatUnraisable() fallback (GH-143557) (GH-143603) 
(#143612)

[3.14] gh-143547: Fix PyErr_FormatUnraisable() fallback (GH-143557) (GH-143603)

gh-143547: Fix PyErr_FormatUnraisable() fallback (GH-143557)

Hold a strong reference to 'hook' while calling the default
unraisable took to log hook failure.
(cherry picked from commit 1d0baf1ae48f98b61cc869a82e1b7206298f653f)


(cherry picked from commit 39a2bcf949095bd603f7b73f15b5b478dbb49ba9)

Co-authored-by: Victor Stinner <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-01-08-14-53-46.gh-issue-143547.wHBVlr.rst
M Lib/test/test_sys.py
M Python/errors.c

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 */
 }
 

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to