Skip to content

Commit c8c162e

Browse files
gh-106030: Miscellaneous fixes in Python/suggestions.c (GH-106031)
* PyDict_GetItem() and PyObject_HasAttr() suppress arbitrary errors and should not be used. * PyUnicode_CompareWithASCIIString() only works if the second argument is ASCII string. * Refleak in get_suggestions_for_name_error. * Use of borrowed pointer after possible freeing (self). * Add some missing error checks.
1 parent 9499b0f commit c8c162e

File tree

1 file changed

+27
-15
lines changed

1 file changed

+27
-15
lines changed

Python/suggestions.c

+27-15
Original file line numberDiff line numberDiff line change
@@ -151,15 +151,15 @@ calculate_suggestions(PyObject *dir,
151151
}
152152
for (int i = 0; i < dir_size; ++i) {
153153
PyObject *item = PyList_GET_ITEM(dir, i);
154+
if (_PyUnicode_Equal(name, item)) {
155+
continue;
156+
}
154157
Py_ssize_t item_size;
155158
const char *item_str = PyUnicode_AsUTF8AndSize(item, &item_size);
156159
if (item_str == NULL) {
157160
PyMem_Free(buffer);
158161
return NULL;
159162
}
160-
if (PyUnicode_CompareWithASCIIString(name, item_str) == 0) {
161-
continue;
162-
}
163163
// No more than 1/3 of the involved characters should need changed.
164164
Py_ssize_t max_distance = (name_size + item_size + 3) * MOVE_COST / 6;
165165
// Don't take matches we've already beaten.
@@ -220,37 +220,48 @@ get_suggestions_for_name_error(PyObject* name, PyFrameObject* frame)
220220
assert(code != NULL && code->co_localsplusnames != NULL);
221221

222222
PyObject *varnames = _PyCode_GetVarnames(code);
223+
Py_DECREF(code);
223224
if (varnames == NULL) {
224225
return NULL;
225226
}
226227
PyObject *dir = PySequence_List(varnames);
227228
Py_DECREF(varnames);
228-
Py_DECREF(code);
229229
if (dir == NULL) {
230230
return NULL;
231231
}
232232

233233
// Are we inside a method and the instance has an attribute called 'name'?
234-
if (PySequence_Contains(dir, &_Py_ID(self)) > 0) {
234+
int res = PySequence_Contains(dir, &_Py_ID(self));
235+
if (res < 0) {
236+
goto error;
237+
}
238+
if (res > 0) {
235239
PyObject* locals = PyFrame_GetLocals(frame);
236240
if (!locals) {
237241
goto error;
238242
}
239-
PyObject* self = PyDict_GetItem(locals, &_Py_ID(self)); /* borrowed */
240-
Py_DECREF(locals);
243+
PyObject* self = PyDict_GetItemWithError(locals, &_Py_ID(self)); /* borrowed */
241244
if (!self) {
245+
Py_DECREF(locals);
242246
goto error;
243247
}
244248

245-
if (PyObject_HasAttr(self, name)) {
249+
PyObject *value;
250+
res = _PyObject_LookupAttr(self, name, &value);
251+
Py_DECREF(locals);
252+
if (res < 0) {
253+
goto error;
254+
}
255+
if (value) {
256+
Py_DECREF(value);
246257
Py_DECREF(dir);
247-
return PyUnicode_FromFormat("self.%S", name);
258+
return PyUnicode_FromFormat("self.%U", name);
248259
}
249260
}
250261

251262
PyObject *suggestions = calculate_suggestions(dir, name);
252263
Py_DECREF(dir);
253-
if (suggestions != NULL) {
264+
if (suggestions != NULL || PyErr_Occurred()) {
254265
return suggestions;
255266
}
256267

@@ -260,7 +271,7 @@ get_suggestions_for_name_error(PyObject* name, PyFrameObject* frame)
260271
}
261272
suggestions = calculate_suggestions(dir, name);
262273
Py_DECREF(dir);
263-
if (suggestions != NULL) {
274+
if (suggestions != NULL || PyErr_Occurred()) {
264275
return suggestions;
265276
}
266277

@@ -319,15 +330,16 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc)
319330
assert(frame != NULL);
320331

321332
PyObject* suggestion = get_suggestions_for_name_error(name, frame);
322-
bool is_stdlib_module = is_name_stdlib_module(name);
323-
324-
if (suggestion == NULL && !is_stdlib_module) {
333+
if (suggestion == NULL && PyErr_Occurred()) {
325334
return NULL;
326335
}
327336

328337
// Add a trailer ". Did you mean: (...)?"
329338
PyObject* result = NULL;
330-
if (!is_stdlib_module) {
339+
if (!is_name_stdlib_module(name)) {
340+
if (suggestion == NULL) {
341+
return NULL;
342+
}
331343
result = PyUnicode_FromFormat(". Did you mean: %R?", suggestion);
332344
} else if (suggestion == NULL) {
333345
result = PyUnicode_FromFormat(". Did you forget to import %R?", name);

0 commit comments

Comments
 (0)