bpo-38530: Make sure that failing to generate suggestions on failure will not propagate exceptions (GH-25408)

This commit is contained in:
Pablo Galindo 2021-04-14 18:58:28 +01:00 committed by GitHub
parent 0c4c436325
commit e07f4ab26a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 7 deletions

View file

@ -1695,6 +1695,20 @@ 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())
self.assertNotIn("oh no!", err.getvalue())
class ImportErrorTests(unittest.TestCase):

View file

@ -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);

View file

@ -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,16 @@ 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
assert(!PyErr_Occurred());
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;
}