[PATCH 11/28] use iterator protocol and avoid refcount bugs

Tom Tromey
2013-04-19T14:32:46Z

The checker pointed out some refcounting bugs in cmdpy_completer.
And, while looking at it, I noticed that it was not using the iterator
protocol. I couldn't think of a reason why not; and using an iterator
cleaned up the code, so this patch does that.

* python/py-cmd.c (cmdpy_completer): Use iterator protocol.
Correctly decref.
---
gdb/python/py-cmd.c | 49 ++++++++++++++++++++++++++++---------------------
1 file changed, 28 insertions(+), 21 deletions(-)

diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c
index 6516e1f..26823c7 100644
--- a/gdb/python/py-cmd.c
+++ b/gdb/python/py-cmd.c
@@ -247,26 +247,40 @@ cmdpy_completer (struct cmd_list_element *command,
make_cleanup_py_decref (resultobj);

result = NULL;
- if (PySequence_Check (resultobj))
+ if (PyInt_Check (resultobj))
{
- Py_ssize_t i, len = PySequence_Size (resultobj);
- Py_ssize_t out;
+ /* User code may also return one of the completion constants,
+ thus requesting that sort of completion. */
+ long value;
+
+ if (! gdb_py_int_as_long (resultobj, &value))
+ {
+ /* Ignore. */
+ PyErr_Clear ();
+ }
+ else if (value >= 0 && value < (long) N_COMPLETERS)
+ result = completers[value].completer (command, text, word);
+ }
+ else
+ {
+ PyObject *iter = PyObject_GetIter (resultobj);
+ PyObject *elt;

- if (len < 0)
+ if (iter == NULL)
goto done;

- for (i = out = 0; i < len; ++i)
+ while ((elt = PyIter_Next (iter)) != NULL)
{
- PyObject *elt = PySequence_GetItem (resultobj, i);
char *item;

- if (elt == NULL || ! gdbpy_is_string (elt))
+ if (! gdbpy_is_string (elt))
{
/* Skip problem elements. */
- PyErr_Clear ();
+ Py_DECREF (elt);
continue;
}
item = python_string_to_host_string (elt);
+ Py_DECREF (elt);
if (item == NULL)
{
/* Skip problem elements. */
@@ -275,20 +289,13 @@ cmdpy_completer (struct cmd_list_element *command,
}
VEC_safe_push (char_ptr, result, item);
}
- }
- else if (PyInt_Check (resultobj))
- {
- /* User code may also return one of the completion constants,
- thus requesting that sort of completion. */
- long value;

- if (! gdb_py_int_as_long (resultobj, &value))
- {
- /* Ignore. */
- PyErr_Clear ();
- }
- else if (value >= 0 && value < (long) N_COMPLETERS)
- result = completers[value].completer (command, text, word);
+ Py_DECREF (iter);
+
+ /* If we got some results, ignore problems. Otherwise, report
+ the problem. */
+ if (result != NULL && PyErr_Occurred ())
+ PyErr_Clear ();
}

done:
--
1.8.1.4