From 67d733f791b1032a5ee4c661f0b037f90c01df87 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 14 Apr 2021 16:00:13 +0100 Subject: [PATCH 1/3] bpo-38530: Clean exceptions if dir() fails when making suggestions for AttributeError --- Lib/test/test_exceptions.py | 13 +++++++++++++ Python/pythonrun.c | 2 ++ Python/suggestions.c | 9 ++------- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 4f3c9ab4563e1f..1d17968bbfca8e 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -1695,6 +1695,19 @@ def __getattr__(self, attr): self.assertIn("blech", err.getvalue()) + def test_attribute_error_with_failing_dict(self): + class T: + bluch = 1 + def __dir__(self): + raise AttributeError("oh no!") + + try: + T().blich + except AttributeError as exc: + with support.captured_stderr() as err: + sys.__excepthook__(*sys.exc_info()) + + self.assertNotIn("blech", err.getvalue()) class ImportErrorTests(unittest.TestCase): diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 321b04eb724ed4..6f84cab702e980 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -962,6 +962,8 @@ print_exception(PyObject *f, PyObject *value) err += PyFile_WriteString("?", f); } Py_DECREF(suggestions); + } else if (PyErr_Occurred()) { + PyErr_Clear(); } err += PyFile_WriteString("\n", f); Py_XDECREF(tb); diff --git a/Python/suggestions.c b/Python/suggestions.c index 058294fc8b6b72..02f555e5a308a5 100644 --- a/Python/suggestions.c +++ b/Python/suggestions.c @@ -89,14 +89,12 @@ calculate_suggestions(PyObject *dir, PyObject *suggestion = NULL; const char *name_str = PyUnicode_AsUTF8(name); if (name_str == NULL) { - PyErr_Clear(); return NULL; } for (int i = 0; i < dir_size; ++i) { PyObject *item = PyList_GET_ITEM(dir, i); const char *item_str = PyUnicode_AsUTF8(item); if (item_str == NULL) { - PyErr_Clear(); return NULL; } Py_ssize_t current_distance = levenshtein_distance(name_str, item_str); @@ -156,7 +154,6 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) { assert(code != NULL && code->co_varnames != NULL); PyObject *dir = PySequence_List(code->co_varnames); if (dir == NULL) { - PyErr_Clear(); return NULL; } @@ -168,7 +165,6 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) { dir = PySequence_List(frame->f_globals); if (dir == NULL) { - PyErr_Clear(); return NULL; } suggestions = calculate_suggestions(dir, name); @@ -178,16 +174,15 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) { } // Offer suggestions for a given exception. Returns a python string object containing the -// suggestions. This function does not raise exceptions and returns NULL if no suggestion was found. +// suggestions. This function returns NULL if no suggestion was found or if an exception happened, +// users must call PyErr_Occurred() to disambiguate. PyObject *_Py_Offer_Suggestions(PyObject *exception) { PyObject *result = NULL; - assert(!PyErr_Occurred()); // Check that we are not going to clean any existing exception if (PyErr_GivenExceptionMatches(exception, PyExc_AttributeError)) { result = offer_suggestions_for_attribute_error((PyAttributeErrorObject *) exception); } else if (PyErr_GivenExceptionMatches(exception, PyExc_NameError)) { result = offer_suggestions_for_name_error((PyNameErrorObject *) exception); } - assert(!PyErr_Occurred()); return result; } From 34fbacbc3835a1c9c37d007d4b9b6b250660d680 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 14 Apr 2021 16:12:01 +0100 Subject: [PATCH 2/3] fixup! bpo-38530: Clean exceptions if dir() fails when making suggestions for AttributeError --- Lib/test/test_exceptions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 1d17968bbfca8e..ebeb67b4512822 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -1708,6 +1708,7 @@ def __dir__(self): sys.__excepthook__(*sys.exc_info()) self.assertNotIn("blech", err.getvalue()) + self.assertNotIn("oh no!", err.getvalue()) class ImportErrorTests(unittest.TestCase): From 433efe4afdeda3e7f612211ab163b6c1c9f31aa1 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 14 Apr 2021 16:15:44 +0100 Subject: [PATCH 3/3] fixup! fixup! bpo-38530: Clean exceptions if dir() fails when making suggestions for AttributeError --- Python/suggestions.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/suggestions.c b/Python/suggestions.c index 02f555e5a308a5..bdc8e2fd1bb080 100644 --- a/Python/suggestions.c +++ b/Python/suggestions.c @@ -178,6 +178,7 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc) { // users must call PyErr_Occurred() to disambiguate. PyObject *_Py_Offer_Suggestions(PyObject *exception) { PyObject *result = NULL; + assert(!PyErr_Occurred()); if (PyErr_GivenExceptionMatches(exception, PyExc_AttributeError)) { result = offer_suggestions_for_attribute_error((PyAttributeErrorObject *) exception); } else if (PyErr_GivenExceptionMatches(exception, PyExc_NameError)) {