diff options
author | Mathieu Duponchelle <mathieu@centricular.com> | 2019-07-16 22:08:04 +0200 |
---|---|---|
committer | Christoph Reiter <reiter.christoph@gmail.com> | 2019-08-11 18:13:35 +0000 |
commit | a102f046a178472278522e3e9d7c0b40ecd52ade (patch) | |
tree | 398c92c4c0a6ed7edc74759b24f5e3a591ce9329 | |
parent | ac576400ecd554879c906791e6638d64bb8bcc2a (diff) | |
download | pygobject-a102f046a178472278522e3e9d7c0b40ecd52ade.tar.gz |
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
-rw-r--r-- | gi/pygobject-object.c | 9 | ||||
-rw-r--r-- | tests/regressextra.c | 40 | ||||
-rw-r--r-- | tests/regressextra.h | 15 | ||||
-rw-r--r-- | tests/test_signal.py | 5 |
4 files changed, 68 insertions, 1 deletions
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): """ |