diff options
-rw-r--r-- | Lib/test/test_exceptions.py | 31 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2021-11-17-08-05-27.bpo-45826.OERoTm.rst | 1 | ||||
-rw-r--r-- | Python/suggestions.c | 14 |
3 files changed, 43 insertions, 3 deletions
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 0f8a8f134b..098804fad5 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -1885,6 +1885,37 @@ class NameErrorTests(unittest.TestCase): self.assertNotIn("something", err.getvalue()) + def test_issue45826(self): + # regression test for bpo-45826 + def f(): + with self.assertRaisesRegex(NameError, 'aaa'): + aab + + try: + f() + except self.failureException: + with support.captured_stderr() as err: + sys.__excepthook__(*sys.exc_info()) + + self.assertIn("aab", err.getvalue()) + + def test_issue45826_focused(self): + def f(): + try: + nonsense + except BaseException as E: + E.with_traceback(None) + raise ZeroDivisionError() + + try: + f() + except ZeroDivisionError: + with support.captured_stderr() as err: + sys.__excepthook__(*sys.exc_info()) + + self.assertIn("nonsense", err.getvalue()) + self.assertIn("ZeroDivisionError", err.getvalue()) + class AttributeErrorTests(unittest.TestCase): def test_attributes(self): diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-11-17-08-05-27.bpo-45826.OERoTm.rst b/Misc/NEWS.d/next/Core and Builtins/2021-11-17-08-05-27.bpo-45826.OERoTm.rst new file mode 100644 index 0000000000..f04373bf2f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-11-17-08-05-27.bpo-45826.OERoTm.rst @@ -0,0 +1 @@ +Fixed a crash when calling ``.with_traceback(None)`` on ``NameError``. This occurs internally in ``unittest.TestCase.assertRaises()``.
\ No newline at end of file diff --git a/Python/suggestions.c b/Python/suggestions.c index 81976ff4f2..d9e69fa7e0 100644 --- a/Python/suggestions.c +++ b/Python/suggestions.c @@ -202,13 +202,21 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) PyTracebackObject *traceback = (PyTracebackObject *) exc->traceback; // borrowed reference // Abort if we don't have a variable name or we have an invalid one // or if we don't have a traceback to work with - if (name == NULL || traceback == NULL || !PyUnicode_CheckExact(name)) { + if (name == NULL || !PyUnicode_CheckExact(name) || + traceback == NULL || !Py_IS_TYPE(traceback, &PyTraceBack_Type) + ) { return NULL; } // Move to the traceback of the exception - while (traceback->tb_next != NULL) { - traceback = traceback->tb_next; + while (1) { + PyTracebackObject *next = traceback->tb_next; + if (next == NULL || !Py_IS_TYPE(next, &PyTraceBack_Type)) { + break; + } + else { + traceback = next; + } } PyFrameObject *frame = traceback->tb_frame; |