[pygobject] Use qdata for wrapper retrieval in toggle reference notifications



commit 27e9f6ede021fc58e952491b67d69c2a5cdd6acb
Author: Simon Feltman <sfeltman src gnome org>
Date:   Tue Oct 1 17:09:39 2013 -0700

    Use qdata for wrapper retrieval in toggle reference notifications
    
    Replace usage of user data holding PyGObject wrappers in toggle ref
    notifications with GObject qdata retrieval. This fixes thread safety issues
    where a toggle notify may be called from another thread during the PyGObject
    wrappers dealloc. In this case the toggle notify is blocked because the GIL
    is held in dealloc, and when it continues, the user data would be holding an
    invalid PyGObject wrapper. Using qdata solves this by ensuring the wrapper
    retrieval is done within the safety of the GIL and may turn up as NULL.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=709223

 gi/_gobject/pygobject.c |   21 ++++++++++++++-------
 1 files changed, 14 insertions(+), 7 deletions(-)
---
diff --git a/gi/_gobject/pygobject.c b/gi/_gobject/pygobject.c
index 126c80e..65d5de9 100644
--- a/gi/_gobject/pygobject.c
+++ b/gi/_gobject/pygobject.c
@@ -592,15 +592,22 @@ pygobject_register_class(PyObject *dict, const gchar *type_name,
 static void
 pyg_toggle_notify (gpointer data, GObject *object, gboolean is_last_ref)
 {
-    PyGObject *self = (PyGObject*) data;
+    PyGObject *self;
     PyGILState_STATE state;
 
     state = pyglib_gil_state_ensure();
 
-    if (is_last_ref)
-       Py_DECREF(self);
-    else
-        Py_INCREF(self);
+    /* Avoid thread safety problems by using qdata for wrapper retrieval
+     * instead of the user data argument.
+     * See: https://bugzilla.gnome.org/show_bug.cgi?id=709223
+     */
+    self = (PyGObject *)g_object_get_qdata (object, pygobject_wrapper_key);
+    if (self) {
+        if (is_last_ref)
+            Py_DECREF(self);
+        else
+            Py_INCREF(self);
+    }
 
     pyglib_gil_state_release(state);
 }
@@ -621,7 +628,7 @@ pygobject_switch_to_toggle_ref(PyGObject *self)
       /* Note that add_toggle_ref will never immediately call back into 
          pyg_toggle_notify */
     Py_INCREF((PyObject *) self);
-    g_object_add_toggle_ref(self->obj, pyg_toggle_notify, self);
+    g_object_add_toggle_ref(self->obj, pyg_toggle_notify, NULL);
     g_object_unref(self->obj);
 }
 
@@ -1178,7 +1185,7 @@ pygobject_clear(PyGObject *self)
     if (self->obj) {
         g_object_set_qdata_full(self->obj, pygobject_wrapper_key, NULL, NULL);
         if (self->inst_dict) {
-            g_object_remove_toggle_ref(self->obj, pyg_toggle_notify, self);
+            g_object_remove_toggle_ref(self->obj, pyg_toggle_notify, NULL);
             self->private_flags.flags &= ~PYGOBJECT_USING_TOGGLE_REF;
         } else {
             Py_BEGIN_ALLOW_THREADS;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]