develooper Front page | perl.perl5.porters | Postings from December 2011

Object destruction changes in 5.15 break Gtk2

Thread Next
From:
Torsten Schoenfeld
Date:
December 10, 2011 10:45
Subject:
Object destruction changes in 5.15 break Gtk2
Message ID:
4EE3A8D8.9020104@gmx.de
[Sorry for getting to this so late.]

The changes to object destruction described in 
<https://rt.perl.org/rt3/Public/Bug/Display.html?id=36347> and 
<http://perl5.git.perl.org/perl.git/commitdiff/4155e4fe> are known to 
break Gtk2 and friends (which I am the maintainer of).  I'd like to fix 
things so that we will work with 5.16, but I'm unsure what the best way 
to do that is.  Let me describe the problem.

Gtk2 uses Glib for most of the heavy lifting, specifically: 
Glib::Object.  Conceptually, Glib::Object wraps ref-counted C objects 
(GObjects) by permanently associating HVs to them and then handing out 
references to the HVs.  If we encounter a GObject for the first time, we 
create a new HV and a new RV pointing to the HV and increase the 
GObject's ref-count.  The RV gets handed to user code.  If we encounter 
that GObject again later, we look up its associated HV, increase the 
GObject's ref-count, and return a new reference to this existing HV. 
Thus, user code always sees references to the same HV and can use it to 
store and retrieve data.

[GObject → SV: 
<http://git.gnome.org/browse/perl-Glib/tree/GObject.xs#n804>.  SV → 
GObject: <http://git.gnome.org/browse/perl-Glib/tree/GObject.xs#n958>.]

Now, if such an RV goes out of scope, we decrease the GObject's 
ref-count.  And since normally the HV would also be destroyed, but we 
want to keep it around, we *in*crement its ref-count in DESTROY and put 
it in an "undead" state.  This way, even if all user-visible references 
to the HV have been dropped, we can still fetch and "revive" the correct 
HV if we see the GObject again.  If the actual GObject is destroyed, we 
get a callback and destroy the HV.

[DESTROY: <http://git.gnome.org/browse/perl-Glib/tree/GObject.xs#n1207>. 
  Callback for GObject destruction: 
<http://git.gnome.org/browse/perl-Glib/tree/GObject.xs#n769>.]

In perl <= 5.14, this worked fine in that we got a call to DESTROY for 
each RV we handed out.  In blead now, during global destruction, we 
actually get an additional call of DESTROY for each HV.  Presumably, the 
changes mentioned above now also see the "undead" HV, create a temporary 
RV for it and invoke DESTROY on it.  That leads to an extra decrement of 
the GObject's ref-count, often resulting in segfaults.

So it seems that we made an implicit assumption: we will not get DESTROY 
calls on HVs which have no RVs pointing to them.  That seems to not hold 
anymore.  So, my question is: is that assumption unreasonable?  If so, 
what should we do to fix our code?

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About