From 5d90c467c02ffefdb13c1abc83a171db1a99ffad Mon Sep 17 00:00:00 2001 From: Dennis Sweeney <36520290+sweeneyde@users.noreply.github.com> Date: Wed, 17 Nov 2021 18:03:52 -0500 Subject: bpo-45826: Fix a crash in suggestions.c by checking for `traceback is None` (GH-29590) --- Lib/test/test_exceptions.py | 31 ++++++++++++++++++++++ .../2021-11-17-08-05-27.bpo-45826.OERoTm.rst | 1 + Python/suggestions.c | 14 +++++++--- 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-11-17-08-05-27.bpo-45826.OERoTm.rst diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 0f8a8f1..098804fad 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 0000000..f04373b --- /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 81976ff..d9e69fa 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; -- cgit v0.12