This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFC: fix PR python/14387


This patch fixes PR python/14387.

The bug here is that we leak a list object because gdb seems to assume
that PyObject_SetAttrString borrows a reference -- but really it
acquires a reference.

I audited all the calls to PyObject_SetAttrString in gdb.  They were all
wrong, so at least we were consistent.

This patch fixes these errors, and also a few various latent
exception-handling bugs that I noticed while doing so.

Occasionally I despair of us ever writing correct Python-using code.
I wish we could use a generator like Cython...

Built and tested on x86-64 Fedora 16.

Tom

commit ca7ec0b6cb91830d0964d233746918618e558a8d
Author: Tom Tromey <tromey@redhat.com>
Date:   Wed Aug 1 11:19:04 2012 -0600

    fix PR python/14387
    
    	PR python/14387:
    	* python/py-bpevent.c (create_breakpoint_event_object): Update
    	comment.
    	* python/py-event.c (evpy_add_attribute): Update comment.
    	* python/py-exitedevent.c (create_exited_event_object): Fix
    	reference counting and error handling.
    	* python/py-newobjfileevent.c (create_new_objfile_event_object):
    	Fix reference counting.
    	* python/py-signalevent.c (create_signal_event_object): Fix
    	reference counting and error handling.
    	* python/py-stopevent.c (emit_stop_event): Fix reference
    	counting.
    	* python/py-threadevent.c (get_event_thread): Return a
    	borrowed reference.
    	* python/py-type.c (convert_field): Fix reference counting.

diff --git a/gdb/python/py-bpevent.c b/gdb/python/py-bpevent.c
index 138c39f0..8e4afe4 100644
--- a/gdb/python/py-bpevent.c
+++ b/gdb/python/py-bpevent.c
@@ -21,7 +21,8 @@
 
 static PyTypeObject breakpoint_event_object_type;
 
-/* Create and initialize a BreakpointEvent object.  */
+/* Create and initialize a BreakpointEvent object.  This acquires new
+   references to BREAKPOINT_LIST and FIRST_BP.  */
 
 PyObject *
 create_breakpoint_event_object (PyObject *breakpoint_list, PyObject *first_bp)
diff --git a/gdb/python/py-event.c b/gdb/python/py-event.c
index 4789761..7c88fcd 100644
--- a/gdb/python/py-event.c
+++ b/gdb/python/py-event.c
@@ -48,7 +48,8 @@ create_event_object (PyTypeObject *py_type)
 
 /* Add the attribute ATTR to the event object EVENT.  In
    python this attribute will be accessible by the name NAME.
-   returns 0 if the operation succeeds and -1 otherwise.  */
+   returns 0 if the operation succeeds and -1 otherwise.  This
+   function acquires a new reference to ATTR.  */
 
 int
 evpy_add_attribute (PyObject *event, char *name, PyObject *attr)
diff --git a/gdb/python/py-exitedevent.c b/gdb/python/py-exitedevent.c
index 272fd30..d062f5f 100644
--- a/gdb/python/py-exitedevent.c
+++ b/gdb/python/py-exitedevent.c
@@ -25,30 +25,41 @@ static PyObject *
 create_exited_event_object (const LONGEST *exit_code, struct inferior *inf)
 {
   PyObject *exited_event;
-  PyObject *inf_obj;
+  PyObject *inf_obj = NULL;
 
   exited_event = create_event_object (&exited_event_object_type);
 
   if (!exited_event)
     goto fail;
 
-  if (exit_code
-      && evpy_add_attribute (exited_event,
-			     "exit_code",
-			     PyLong_FromLongLong (*exit_code)) < 0)
-    goto fail;
+  if (exit_code)
+    {
+      PyObject *exit_code_obj = PyLong_FromLongLong (*exit_code);
+      int failed;
+
+      if (exit_code_obj == NULL)
+	goto fail;
+
+      failed = evpy_add_attribute (exited_event, "exit_code",
+				   exit_code_obj) < 0;
+      Py_DECREF (exit_code_obj);
+      if (failed)
+	goto fail;
+    }
 
   inf_obj = inferior_to_inferior_object (inf);
   if (!inf_obj || evpy_add_attribute (exited_event,
                                       "inferior",
                                       inf_obj) < 0)
     goto fail;
+  Py_DECREF (inf_obj);
 
   return exited_event;
 
-  fail:
-   Py_XDECREF (exited_event);
-   return NULL;
+ fail:
+  Py_XDECREF (inf_obj);
+  Py_XDECREF (exited_event);
+  return NULL;
 }
 
 /* Callback that is used when an exit event occurs.  This function
diff --git a/gdb/python/py-newobjfileevent.c b/gdb/python/py-newobjfileevent.c
index d014be6..3059ae4 100644
--- a/gdb/python/py-newobjfileevent.c
+++ b/gdb/python/py-newobjfileevent.c
@@ -25,7 +25,7 @@ static PyObject *
 create_new_objfile_event_object (struct objfile *objfile)
 {
   PyObject *objfile_event;
-  PyObject *py_objfile;
+  PyObject *py_objfile = NULL;
 
   objfile_event = create_event_object (&new_objfile_event_object_type);
   if (!objfile_event)
@@ -36,10 +36,12 @@ create_new_objfile_event_object (struct objfile *objfile)
                                          "new_objfile",
                                          py_objfile) < 0)
     goto fail;
+  Py_DECREF (py_objfile);
 
   return objfile_event;
 
  fail:
+  Py_XDECREF (py_objfile);
   Py_XDECREF (objfile_event);
   return NULL;
 }
diff --git a/gdb/python/py-signalevent.c b/gdb/python/py-signalevent.c
index 304b847..40da31a 100644
--- a/gdb/python/py-signalevent.c
+++ b/gdb/python/py-signalevent.c
@@ -25,6 +25,7 @@ PyObject *
 create_signal_event_object (enum gdb_signal stop_signal)
 {
   const char *signal_name;
+  PyObject *signal_name_obj = NULL;
   PyObject *signal_event_obj =
       create_stop_event_object (&signal_event_object_type);
 
@@ -33,16 +34,21 @@ create_signal_event_object (enum gdb_signal stop_signal)
 
   signal_name = gdb_signal_to_name (stop_signal);
 
+  signal_name_obj = PyString_FromString (signal_name);
+  if (signal_name_obj == NULL)
+    goto fail;
   if (evpy_add_attribute (signal_event_obj,
                           "stop_signal",
-                          PyString_FromString (signal_name)) < 0)
+                          signal_name_obj) < 0)
     goto fail;
+  Py_DECREF (signal_name_obj);
 
   return signal_event_obj;
 
-  fail:
-   Py_XDECREF (signal_event_obj);
-   return NULL;
+ fail:
+  Py_XDECREF (signal_name_obj);
+  Py_XDECREF (signal_event_obj);
+  return NULL;
 }
 
 GDBPY_NEW_EVENT_TYPE (signal,
diff --git a/gdb/python/py-stopevent.c b/gdb/python/py-stopevent.c
index 7e00948..d351915 100644
--- a/gdb/python/py-stopevent.c
+++ b/gdb/python/py-stopevent.c
@@ -81,6 +81,7 @@ emit_stop_event (struct bpstats *bs, enum gdb_signal stop_signal)
       stop_event_obj = create_breakpoint_event_object (list, first_bp);
       if (!stop_event_obj)
         goto fail;
+      Py_DECREF (list);
     }
 
   /* Check if the signal is "Signal 0" or "Trace/breakpoint trap".  */
diff --git a/gdb/python/py-threadevent.c b/gdb/python/py-threadevent.c
index 67f9e20..d513945 100644
--- a/gdb/python/py-threadevent.c
+++ b/gdb/python/py-threadevent.c
@@ -21,7 +21,7 @@
    running in non-stop mode then the event is thread specific, otherwise
    it is process wide.
    This function returns the currently stopped thread in non-stop mode and
-   Py_None otherwise.  */
+   Py_None otherwise.  In each case it returns a borrowed reference.  */
 
 static PyObject *
 get_event_thread (void)
@@ -39,8 +39,6 @@ get_event_thread (void)
       return NULL;
     }
 
-  Py_INCREF (thread);
-
   return thread;
 }
 
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index 98030a6..5239342 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -186,6 +186,7 @@ convert_field (struct type *type, int field)
       /* At least python-2.4 had the second parameter non-const.  */
       if (PyObject_SetAttrString (result, (char *) attrstring, arg) < 0)
 	goto failarg;
+      Py_DECREF (arg);
     }
 
   if (TYPE_FIELD_NAME (type, field))
@@ -199,11 +200,13 @@ convert_field (struct type *type, int field)
     goto fail;
   if (PyObject_SetAttrString (result, "name", arg) < 0)
     goto failarg;
+  Py_DECREF (arg);
 
   arg = TYPE_FIELD_ARTIFICIAL (type, field) ? Py_True : Py_False;
   Py_INCREF (arg);
   if (PyObject_SetAttrString (result, "artificial", arg) < 0)
     goto failarg;
+  Py_DECREF (arg);
 
   if (TYPE_CODE (type) == TYPE_CODE_CLASS)
     arg = field < TYPE_N_BASECLASSES (type) ? Py_True : Py_False;
@@ -212,12 +215,14 @@ convert_field (struct type *type, int field)
   Py_INCREF (arg);
   if (PyObject_SetAttrString (result, "is_base_class", arg) < 0)
     goto failarg;
+  Py_DECREF (arg);
 
   arg = PyLong_FromLong (TYPE_FIELD_BITSIZE (type, field));
   if (!arg)
     goto fail;
   if (PyObject_SetAttrString (result, "bitsize", arg) < 0)
     goto failarg;
+  Py_DECREF (arg);
 
   /* A field can have a NULL type in some situations.  */
   if (TYPE_FIELD_TYPE (type, field) == NULL)
@@ -231,6 +236,7 @@ convert_field (struct type *type, int field)
     goto fail;
   if (PyObject_SetAttrString (result, "type", arg) < 0)
     goto failarg;
+  Py_DECREF (arg);
 
   return result;
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]