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

1 file changed

Lines changed: 27 additions & 15 deletions

File tree

‎Python/suggestions.c‎

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -151,15 +151,15 @@ calculate_suggestions(PyObject *dir,
151151
}
152152
for (inti=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_titem_size;
155158
constchar*item_str=PyUnicode_AsUTF8AndSize(item, &item_size);
156159
if (item_str==NULL) {
157160
PyMem_Free(buffer);
158161
returnNULL;
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_tmax_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
returnNULL;
225226
}
226227
PyObject*dir=PySequence_List(varnames);
227228
Py_DECREF(varnames);
228-
Py_DECREF(code);
229229
if (dir==NULL) {
230230
returnNULL;
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+
intres=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-
returnPyUnicode_FromFormat("self.%S", name);
258+
returnPyUnicode_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
returnsuggestions;
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
returnsuggestions;
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-
boolis_stdlib_module=is_name_stdlib_module(name);
323-
324-
if (suggestion==NULL&& !is_stdlib_module) {
333+
if (suggestion==NULL&&PyErr_Occurred()) {
325334
returnNULL;
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+
returnNULL;
342+
}
331343
result=PyUnicode_FromFormat(". Did you mean: %R?", suggestion);
332344
} elseif (suggestion==NULL) {
333345
result=PyUnicode_FromFormat(". Did you forget to import %R?", name);

0 commit comments

Comments
 (0)