diff --git a/Lib/test/test_warnings.py b/Lib/test/test_warnings.py --- a/Lib/test/test_warnings.py +++ b/Lib/test/test_warnings.py @@ -5,7 +5,7 @@ import sys import unittest from test import support -from test.script_helper import assert_python_ok +from test.script_helper import assert_python_ok, assert_python_failure from test import warning_tests @@ -862,6 +862,32 @@ # of the script self.assertEqual(err, b'__main__:7: UserWarning: test') + def test_issue22898(self): + # Should not crash when interp->sysdict is NULL at the end of Python + # finalization. + code = """if 1: + import sys, traceback + + class MyException(Exception): + def __init__(self, *args): + 1/0 + + def gen(): + f = open('%s') + yield + + g = gen() + next(g) + recursionlimit = sys.getrecursionlimit() + sys.setrecursionlimit(len(traceback.extract_stack())) + try: + g.throw(MyException) + finally: + sys.setrecursionlimit(recursionlimit) + """ % __file__ + rc, out, err = assert_python_failure("-c", code) + # Check that the program does not fail with SIGSEV or SIGABRT. + self.assertEqual(rc, 1) def setUpModule(): py_warnings.onceregistry.clear() diff --git a/Python/_warnings.c b/Python/_warnings.c --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -520,26 +520,37 @@ *module = NULL; - /* Setup registry. */ - assert(globals != NULL); - assert(PyDict_Check(globals)); - *registry = PyDict_GetItemString(globals, "__warningregistry__"); - if (*registry == NULL) { - int rc; + /* during Python finalization, warnings may be emited after interp->sysdict + is cleared: see issue #22898 */ + if (globals != NULL) { + /* Setup registry. */ + assert(PyDict_Check(globals)); + *registry = PyDict_GetItemString(globals, "__warningregistry__"); + if (*registry == NULL) { + int rc; - *registry = PyDict_New(); - if (*registry == NULL) - return 0; + *registry = PyDict_New(); + if (*registry == NULL) + return 0; - rc = PyDict_SetItemString(globals, "__warningregistry__", *registry); - if (rc < 0) - goto handle_error; + rc = PyDict_SetItemString(globals, "__warningregistry__", *registry); + if (rc < 0) + goto handle_error; + } + else + Py_INCREF(*registry); + + /* Setup module. */ + *module = PyDict_GetItemString(globals, "__name__"); } - else - Py_INCREF(*registry); + else { + /* Set module to None to ignore the warning and do nothing. */ + *module = Py_None; + Py_INCREF(*module); + *registry = NULL; + return 0; + } - /* Setup module. */ - *module = PyDict_GetItemString(globals, "__name__"); if (*module == NULL) { *module = PyUnicode_FromString(""); if (*module == NULL) @@ -665,7 +676,7 @@ res = warn_explicit(category, message, filename, lineno, module, registry, NULL); Py_DECREF(filename); - Py_DECREF(registry); + Py_XDECREF(registry); Py_DECREF(module); return res; }