[perl-Glib-Object-Introspection] Handle GInitiallyUnowned return values from callbacks more specifically
- From: Torsten SchÃnfeld <tsch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [perl-Glib-Object-Introspection] Handle GInitiallyUnowned return values from callbacks more specifically
- Date: Fri, 8 Feb 2013 00:38:32 +0000 (UTC)
commit 8753c08c82bd18c59e5eecc8802f9eecb5695701
Author: Torsten SchÃnfeld <kaffeetisch gmx de>
Date: Fri Feb 8 01:35:27 2013 +0100
Handle GInitiallyUnowned return values from callbacks more specifically
Only add an additional ref if the object would otherwise be destroyed. Also,
warn when this happens.
gperl-i11n-invoke-perl.c | 16 --
gperl-i11n-marshal-interface.c | 17 ++-
t/{vfunc-implementation.t => vfunc-chaining.t} | 0
t/vfunc-ref-counting.t | 237 ++++++++++++++++++++++++
4 files changed, 250 insertions(+), 20 deletions(-)
---
diff --git a/gperl-i11n-invoke-perl.c b/gperl-i11n-invoke-perl.c
index e2828d8..f4e2e9e 100644
--- a/gperl-i11n-invoke-perl.c
+++ b/gperl-i11n-invoke-perl.c
@@ -369,22 +369,6 @@ _prepare_perl_invocation_info (GPerlI11nInvocationInfo *iinfo,
iinfo->return_type_transfer = g_callable_info_get_caller_owns (info);
iinfo->dynamic_stack_offset = 0;
-
- /* If the callback is supposed to return a GInitiallyUnowned object
- * then we must enforce GI_TRANSFER_EVERYTHING. Otherwise, if the Perl
- * code returns a newly created object, FREETMPS would finalize it. */
- if (g_type_info_get_tag (iinfo->return_type_info) == GI_TYPE_TAG_INTERFACE &&
- iinfo->return_type_transfer == GI_TRANSFER_NOTHING)
- {
- GIBaseInfo *interface = g_type_info_get_interface (iinfo->return_type_info);
- if (GI_IS_REGISTERED_TYPE_INFO (interface) &&
- g_type_is_a (get_gtype (interface),
- G_TYPE_INITIALLY_UNOWNED))
- {
- iinfo->return_type_transfer = GI_TRANSFER_EVERYTHING;
- }
- g_base_info_unref (interface);
- }
}
static void
diff --git a/gperl-i11n-marshal-interface.c b/gperl-i11n-marshal-interface.c
index 09025d0..223bb14 100644
--- a/gperl-i11n-marshal-interface.c
+++ b/gperl-i11n-marshal-interface.c
@@ -124,10 +124,19 @@ sv_to_interface (GIArgInfo * arg_info,
} else {
arg->v_pointer = gperl_get_object_check (sv, get_gtype (interface));
}
- if (arg->v_pointer && transfer >= GI_TRANSFER_CONTAINER) {
- g_object_ref (arg->v_pointer);
- if (G_IS_INITIALLY_UNOWNED (arg->v_pointer)) {
- g_object_force_floating (arg->v_pointer);
+ if (arg->v_pointer) {
+ GObject *object = arg->v_pointer;
+ if (transfer == GI_TRANSFER_NOTHING &&
+ object->ref_count == 1 &&
+ SvTEMP (sv) && SvREFCNT (SvRV (sv)) == 1)
+ {
+ cwarn ("*** Asked to hand out object without ownership transfer, "
+ "but object is about to be destroyed; "
+ "adding an additional reference for safety");
+ transfer = GI_TRANSFER_EVERYTHING;
+ }
+ if (transfer >= GI_TRANSFER_CONTAINER) {
+ g_object_ref (arg->v_pointer);
}
}
break;
diff --git a/t/vfunc-implementation.t b/t/vfunc-chaining.t
similarity index 100%
rename from t/vfunc-implementation.t
rename to t/vfunc-chaining.t
diff --git a/t/vfunc-ref-counting.t b/t/vfunc-ref-counting.t
new file mode 100644
index 0000000..f3c26a5
--- /dev/null
+++ b/t/vfunc-ref-counting.t
@@ -0,0 +1,237 @@
+#!/usr/bin/env perl
+
+BEGIN { require './t/inc/setup.pl' };
+
+use strict;
+use warnings;
+use Scalar::Util;
+
+plan skip_all => 'Need gobject-introspection 1.35.5'
+ unless check_gi_version (1, 35, 5);
+plan tests => 68;
+
+my @packages = qw/WeakNonFloater WeakFloater StrongNonFloater StrongFloater/;
+my %package_to_subclass = (
+ WeakNonFloater => 'NonFloatingObjectSubclass',
+ WeakFloater => 'FloatingObjectSubclass',
+ StrongNonFloater => 'NonFloatingObjectSubclass',
+ StrongFloater => 'FloatingObjectSubclass',
+);
+my %package_to_warner = (
+ WeakNonFloater => sub { die $_[0] if -1 == index $_[0], 'Asked to hand out object' },
+ WeakFloater => sub { die $_[0] if -1 == index $_[0], 'Asked to hand out object' },
+ StrongNonFloater => sub { die $_[0] },
+ StrongFloater => sub { die $_[0] },
+);
+my %package_to_ref_count_offset = (
+ WeakNonFloater => 0,
+ WeakFloater => 0,
+ StrongNonFloater => 1,
+ StrongFloater => 1,
+);
+my %package_to_ref_gone = (
+ WeakNonFloater => Glib::TRUE,
+ WeakFloater => Glib::TRUE,
+ StrongNonFloater => Glib::FALSE,
+ StrongFloater => Glib::FALSE,
+);
+my %package_to_floating = (
+ WeakNonFloater => Glib::FALSE,
+ WeakFloater => Glib::TRUE,
+ StrongNonFloater => Glib::FALSE,
+ StrongFloater => Glib::TRUE,
+);
+
+# Test that the invocant is not leaked.
+foreach my $package (@packages) {
+ {
+ my $nf = $package->new;
+ $nf->get_ref_info_for_vfunc_return_object_transfer_full;
+ Scalar::Util::weaken ($nf);
+ is ($nf, undef, "no leak for $package");
+ }
+}
+
+# Test transfer-none&return/out semantics.
+foreach my $package (@packages) {
+ local $SIG{__WARN__} = $package_to_warner{$package};
+ foreach my $method (qw/get_ref_info_for_vfunc_return_object_transfer_none
+ get_ref_info_for_vfunc_out_object_transfer_none/)
+ {
+ my $nf = $package->new;
+ my ($ref_count, $is_floating) = $nf->$method;
+ is ($ref_count, 1, "transfer-none&return/out: ref count for $package");
+ ok (!$is_floating, "transfer-none&return/out: floating for $package");
+ }
+}
+
+# Test transfer-full&return/out semantics.
+foreach my $package (@packages) {
+ foreach my $method (qw/get_ref_info_for_vfunc_return_object_transfer_full
+ get_ref_info_for_vfunc_out_object_transfer_full/)
+ {
+ my $nf = $package->new;
+ my ($ref_count, $is_floating) = $nf->$method;
+ is ($ref_count, 1 + $package_to_ref_count_offset{$package},
+ "transfer-full&return/out: ref count for $package");
+ ok (!$is_floating, "transfer-full&return/out: floating for $package");
+ is ($nf->is_ref_gone, $package_to_ref_gone{$package},
+ "transfer-full&return/out: ref gone for $package");
+ }
+}
+
+# Test transfer-none&in semantics.
+foreach my $package (@packages) {
+ {
+ my $nf = $package->new;
+ my ($ref_count, $is_floating) =
+ $nf->get_ref_info_for_vfunc_in_object_transfer_none ($package_to_subclass{$package});
+ SKIP: {
+ skip 'ref count test; need newer Glib', 1
+ unless $Glib::VERSION > 1.290;
+ is ($ref_count, 1 + $package_to_ref_count_offset{$package},
+ "transfer-none&in: ref count for $package");
+ }
+ is ($is_floating, $package_to_floating{$package},
+ "transfer-none&in: floating for $package");
+ is ($nf->is_ref_gone, $package_to_ref_gone{$package},
+ "transfer-none&in: ref gone for $package");
+ }
+}
+
+# Test transfer-full&in semantics.
+foreach my $package (@packages) {
+ {
+ my $nf = $package->new;
+ my ($ref_count, $is_floating) =
+ $nf->get_ref_info_for_vfunc_in_object_transfer_full ($package_to_subclass{$package});
+ SKIP: {
+ skip 'ref count test; need newer Glib', 1
+ unless $Glib::VERSION > 1.290;
+ is ($ref_count, 0 + $package_to_ref_count_offset{$package},
+ "transfer-full&in: ref count for $package");
+ }
+ ok (!$is_floating, "transfer-full&in: floating for $package");
+ is ($nf->is_ref_gone, $package_to_ref_gone{$package},
+ "transfer-full&in: ref gone for $package");
+ }
+}
+
+# --------------------------------------------------------------------------- #
+
+{
+ package NonFloatingObjectSubclass;
+ use Glib::Object::Subclass 'Glib::Object';
+}
+
+{
+ package FloatingObjectSubclass;
+ use Glib::Object::Subclass 'Glib::InitiallyUnowned';
+}
+
+{
+ package Base;
+ use Glib::Object::Subclass 'GI::Object';
+
+ sub VFUNC_RETURN_OBJECT_TRANSFER_NONE {
+ my ($self) = @_;
+ my $o = $self->_create;
+ $self->_store ($o);
+ return $o;
+ }
+ sub VFUNC_RETURN_OBJECT_TRANSFER_FULL {
+ my ($self) = @_;
+ my $o = $self->_create;
+ $self->_store ($o);
+ return $o;
+ }
+ sub VFUNC_OUT_OBJECT_TRANSFER_NONE {
+ my ($self) = @_;
+ my $o = $self->_create;
+ $self->_store ($o);
+ return $o;
+ }
+ sub VFUNC_OUT_OBJECT_TRANSFER_FULL {
+ my ($self) = @_;
+ my $o = $self->_create;
+ $self->_store ($o);
+ return $o;
+ }
+ sub VFUNC_IN_OBJECT_TRANSFER_NONE {
+ my ($self, $o) = @_;
+ $self->_store ($o);
+ }
+ sub VFUNC_IN_OBJECT_TRANSFER_FULL {
+ my ($self, $o) = @_;
+ $self->_store ($o);
+ }
+
+ sub is_ref_gone {
+ my ($self) = @_;
+ not defined $self->_retrieve;
+ }
+}
+{
+ package WeakNonFloater;
+ use Glib::Object::Subclass 'Base';
+
+ sub _create {
+ NonFloatingObjectSubclass->new;
+ }
+ sub _store {
+ my ($self, $o) = @_;
+ Scalar::Util::weaken ($self->{_ref} = $o);
+ }
+ sub _retrieve {
+ my ($self) = @_;
+ $self->{_ref};
+ }
+}
+{
+ package WeakFloater;
+ use Glib::Object::Subclass 'Base';
+
+ sub _create {
+ FloatingObjectSubclass->new;
+ }
+ sub _store {
+ my ($self, $o) = @_;
+ Scalar::Util::weaken ($self->{_ref} = $o);
+ }
+ sub _retrieve {
+ my ($self) = @_;
+ $self->{_ref};
+ }
+}
+{
+ package StrongNonFloater;
+ use Glib::Object::Subclass 'Base';
+
+ sub _create {
+ NonFloatingObjectSubclass->new;
+ }
+ sub _store {
+ my ($self, $o) = @_;
+ $self->{_ref} = $o;
+ }
+ sub _retrieve {
+ my ($self) = @_;
+ $self->{_ref};
+ }
+}
+{
+ package StrongFloater;
+ use Glib::Object::Subclass 'Base';
+
+ sub _create {
+ FloatingObjectSubclass->new;
+ }
+ sub _store {
+ my ($self, $o) = @_;
+ $self->{_ref} = $o;
+ }
+ sub _retrieve {
+ my ($self) = @_;
+ $self->{_ref};
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]