After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 661576 - fix handling of constructors that destroy half-constructed objects
fix handling of constructors that destroy half-constructed objects
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: gobject
unspecified
Other All
: Normal normal
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2011-10-12 18:11 UTC by Dan Winship
Modified: 2014-02-15 15:22 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
gobject: fix handling of constructors that destroy half-constructed objects (1.38 KB, patch)
2011-10-12 18:11 UTC, Dan Winship
none Details | Review
gobject: fix a crash when constructor() disposes the object it creates (22.03 KB, patch)
2013-04-30 14:17 UTC, Dan Winship
none Details | Review
to be squashed: forbid finalization-during-construction (6.09 KB, patch)
2013-04-30 20:29 UTC, Dan Winship
none Details | Review
gobject: forbid finalization-during-construction (7.16 KB, patch)
2013-10-20 14:04 UTC, Dan Winship
committed Details | Review
gobject: simplify object-in-construction handling (6.69 KB, patch)
2013-10-20 14:05 UTC, Dan Winship
committed Details | Review
gobject: re-allow finalization from constructor() (2.95 KB, patch)
2013-12-02 17:03 UTC, Dan Winship
committed Details | Review

Description Dan Winship 2011-10-12 18:11:36 UTC
slightly weird...

I have a class that overrides constructor(), chains down, and then
looks at the constructed object to see if it "matches" any of the
objects in its cache. If it does match, then the newly-created object
is unreffed, and the constructor() returns the cached object (adding a
ref) instead.

(It would be possible in theory to skip the chain-down-construct-unref
step, and just process all the construct params by hand to figure out
whether or not this object was going to end up matching another one...
but that would be annoying, so I didn't.)

Anyway, in this case, the infanticided object ends up getting left
behind on gobject.c's construction_objects list, which will cause
problems later when that memory location gets reused for a different
object. (In particular, when I try to return that new object from the
cache, I get:

GLib-GObject-CRITICAL **: g_object_notify_queue_thaw: assertion
`nqueue->freeze_count > 0' failed

because gobject thinks it's newly-constructed now, because it was on
the list.)


Even if the answer is "you can't do that", maybe it's worth throwing
an error when the infanticide occurs, rather than
non-deterministically throwing one later?
Comment 1 Dan Winship 2011-10-12 18:11:38 UTC
Created attachment 198870 [details] [review]
gobject: fix handling of constructors that destroy half-constructed objects

If a GObject constructor implementation chains down to create an
object, but then destroys it and returns a different object instead,
then the object would get left in the construction_objects list, which
would confuse things if another object was created later at the same
location in memory.
Comment 2 Dan Winship 2013-04-30 14:17:29 UTC
Created attachment 242917 [details] [review]
gobject: fix a crash when constructor() disposes the object it creates

If a constructor() implementation created an object but then didn't
return it, that object would get left on the construction_objects
list, which would cause problems later when that memory location got
reused by another object.

Fix this by keep the "in construction" state in the object's qdata
rather than in a global variable.

Add some tests to verify that this case and the more common
constructor-returning-a-singleton case work, and another test
verifying that construct-only properties work as expected.

=====

(inspired by bug 698983...)
Comment 3 Allison Karlitskaya (desrt) 2013-04-30 16:51:53 UTC
Review of attachment 242917 [details] [review]:

I like this other than the fact that we're fixing bugs in a broken behaviour during the same release cycle as we officially declare it as "this has always been broken, don't use it".

In general, I don't want to increase the incentive to use constructor() more....

That said, this patch is very obviously an improvement.  In fact, the only bad thing I can say about it is that it might encourage more people to use this code...

::: gobject/gobject.c
@@ +1641,3 @@
     {
+      g_critical ("Custom constructor for class %s returned NULL (which is invalid)."
+                  "Please use GInitable instead.", G_OBJECT_CLASS_NAME (class));

thanks for keeping this...
Comment 4 Dan Winship 2013-04-30 20:29:05 UTC
Created attachment 242963 [details] [review]
to be squashed: forbid finalization-during-construction

As an alternative to the previous patch, we could make
finalization-during-construction intentionally fail, rather than
having it merely accidentally fail.

(The rest of the previous patch is still worth applying, since it
makes the in-construction handling nicer.)
Comment 5 Dan Winship 2013-10-20 14:04:54 UTC
Created attachment 257758 [details] [review]
gobject: forbid finalization-during-construction

If a constructor() implementation created an object but then unreffed
it rather than returning it, that object would get left on the
construction_objects list, which would cause problems later when that
memory location got reused by another object.

"Fix" this by making it fail intentionally, and add a test for it (and
for the normal, working singleton case).
Comment 6 Dan Winship 2013-10-20 14:05:02 UTC
Created attachment 257759 [details] [review]
gobject: simplify object-in-construction handling

Rather than keeping a global list of objects that are being
constructed, use qdata on the object itself like we do with several
other properties now.
Comment 7 Allison Karlitskaya (desrt) 2013-10-22 14:40:04 UTC
Review of attachment 257758 [details] [review]:

I'm pretty happy with this.  Thanks for formalising it.
Comment 8 Allison Karlitskaya (desrt) 2013-10-22 14:41:29 UTC
Review of attachment 257759 [details] [review]:

I don't have a strong opinion on this topic because this code is so rarely used.  One less mutex with complicated list-mangling code is good, I guess.  Commit it if you prefer it this way.
Comment 9 Dan Winship 2013-10-22 15:02:37 UTC
Attachment 257758 [details] pushed as 0d62eb4 - gobject: forbid finalization-during-construction
Attachment 257759 [details] pushed as efecfe0 - gobject: simplify object-in-construction handling
Comment 10 Dan Winship 2013-12-02 17:03:49 UTC
this is turning out to have some unintended fallout
Comment 11 Dan Winship 2013-12-02 17:03:58 UTC
Created attachment 263315 [details] [review]
gobject: re-allow finalization from constructor()

Although returning NULL from constructor is strongly discouraged, some
old libraries need to keep doing it for ABI-compatibility reasons.
Given this, it's rude to forbid finalization from within
constructor(), since it would otherwise work correctly now anyway (and
the critical when returning NULL should discourage any new uses of
returning NULL from constructor()).
Comment 12 Allison Karlitskaya (desrt) 2013-12-02 18:17:01 UTC
Review of attachment 263315 [details] [review]:

::: gobject/gobject.c
@@ -1028,3 @@
-  if (object_in_construction (object))
-    {
-      g_error ("object %s %p finalized while still in-construction",

Can we just change this to a g_critical()?  I'd rather keep both warnings.
Comment 13 Dan Winship 2014-02-15 15:22:04 UTC
ok, pushed with the g_error() changed to g_critical() rather than
being removed entirely

Attachment 263315 [details] pushed as 5cab3fc - gobject: re-allow finalization from constructor()