[pygobject] pygobject-object: fix refcount of floating return values



commit a102f046a178472278522e3e9d7c0b40ecd52ade
Author: Mathieu Duponchelle <mathieu centricular com>
Date:   Tue Jul 16 22:08:04 2019 +0200

    pygobject-object: fix refcount of floating return values
    
    When g_signal_emitv returns a floating reference as the return
    value, which we end up ref_sinking, do not unset the GValue,
    as we've taken ownership from it and don't want it to drop its
    reference.
    
    Adds a test that highlights the issue

 gi/pygobject-object.c |  9 ++++++++-
 tests/regressextra.c  | 40 ++++++++++++++++++++++++++++++++++++++++
 tests/regressextra.h  | 15 +++++++++++++++
 tests/test_signal.py  |  5 +++++
 4 files changed, 68 insertions(+), 1 deletion(-)
---
diff --git a/gi/pygobject-object.c b/gi/pygobject-object.c
index 39c03ca3..bf969953 100644
--- a/gi/pygobject-object.c
+++ b/gi/pygobject-object.c
@@ -1935,8 +1935,15 @@ pygobject_emit(PyGObject *self, PyObject *args)
     
     g_free(params);
     if ((query.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE) != G_TYPE_NONE) {
+      gboolean was_floating = FALSE;
+
+      if (G_VALUE_HOLDS_OBJECT (&ret)) {
+        GObject *obj = g_value_get_object (&ret);
+        was_floating = g_object_is_floating (obj);
+      }
        py_ret = pyg_value_as_pyobject(&ret, TRUE);
-       g_value_unset(&ret);
+      if (!was_floating)
+             g_value_unset(&ret);
     } else {
        Py_INCREF(Py_None);
        py_ret = Py_None;
diff --git a/tests/regressextra.c b/tests/regressextra.c
index d6af90bf..7e53373a 100644
--- a/tests/regressextra.c
+++ b/tests/regressextra.c
@@ -336,3 +336,43 @@ regress_test_cairo_matrix_out_caller_allocates (cairo_matrix_t *matrix)
 }
 
 #endif
+
+G_DEFINE_TYPE (RegressTestAction, regress_test_action, G_TYPE_INITIALLY_UNOWNED)
+
+enum
+{
+    SIGNAL_0,
+    ACTION_SIGNAL,
+    LAST_SIGNAL
+};
+
+static guint regress_test_action_signals[LAST_SIGNAL] = { 0 };
+
+static RegressTestAction *
+regress_test_action_do_action (RegressTestAction *self)
+{
+    RegressTestAction *ret = g_object_new (regress_test_action_get_type (), NULL);
+
+    return ret;
+}
+
+static void
+regress_test_action_init (RegressTestAction *self)
+{
+}
+
+static void regress_test_action_class_init (RegressTestActionClass *klass)
+{
+    /**
+     * RegressTestAction::action:
+     *
+     * An action signal.
+     *
+     * Returns: (transfer full): another #RegressTestAction
+     */
+    regress_test_action_signals[ACTION_SIGNAL] =
+        g_signal_new_class_handler ("action",
+        G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+        G_CALLBACK (regress_test_action_do_action), NULL, NULL,
+        NULL, regress_test_action_get_type (), 0);
+}
diff --git a/tests/regressextra.h b/tests/regressextra.h
index 0b40ab04..7fc30fe9 100644
--- a/tests/regressextra.h
+++ b/tests/regressextra.h
@@ -1,6 +1,8 @@
 #ifndef REGRESS_EXTRA_H
 #define REGRESS_EXTRA_H
 
+#include <glib-object.h>
+
 typedef struct _RegressTestBoxedC RegressTestBoxedC;
 typedef struct _RegressTestBoxedCWrapper RegressTestBoxedCWrapper;
 
@@ -62,4 +64,17 @@ void regress_test_cairo_matrix_out_caller_allocates (cairo_matrix_t *matrix);
 
 #endif
 
+/* RegressTestAction */
+
+typedef struct {
+  GInitiallyUnowned parent;
+} RegressTestAction;
+
+typedef struct {
+  GInitiallyUnownedClass parent_class;
+} RegressTestActionClass;
+
+_GI_TEST_EXTERN
+GType regress_test_action_get_type (void);
+
 #endif /* REGRESS_EXTRA_H */
diff --git a/tests/test_signal.py b/tests/test_signal.py
index 16d95c27..edc970fc 100644
--- a/tests/test_signal.py
+++ b/tests/test_signal.py
@@ -1243,6 +1243,11 @@ class TestIntrospectedSignals(unittest.TestCase):
         # Boxed equality checks pointers by default.
         self.assertNotEqual(struct, held_struct)
 
+    def test_action(self):
+        obj = Regress.TestAction()
+        other_obj = obj.emit('action')
+        self.assertEqual(other_obj.__grefcount__, 1)
+
 
 class TestIntrospectedSignalsIssue158(unittest.TestCase):
     """


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