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 350200 - [PATCH] GTypeModule derived class unref does not unload plugin
[PATCH] GTypeModule derived class unref does not unload plugin
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: gobject
unspecified
Other Linux
: Normal normal
: ---
Assigned To: Tim Janik
gtkdev
Depends on:
Blocks:
 
 
Reported: 2006-08-06 22:32 UTC by Ronald Bultje
Modified: 2009-10-15 02:27 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
app.c (1.41 KB, text/plain)
2006-08-06 22:33 UTC, Ronald Bultje
  Details
mod.c (1.48 KB, text/plain)
2006-08-06 22:34 UTC, Ronald Bultje
  Details
Fix parent class leak during derived class initialization (864 bytes, patch)
2009-10-14 13:01 UTC, Tim Janik
committed Details | Review

Description Ronald Bultje 2006-08-06 22:32:27 UTC
Attached are a sample app (app.c) and a sample lib (lib.c) to reproduce the bug. The application will load a plugin using GModule/GTypeModule (77 LOC). The lib (72 LOC) implements two types, one derived from GObject, and a second derived from this first one (both using the same macros). All the object/plugin do is printf() what is going on.

Instantiating and unloading the first type (GObject-derived) properly leads to unloading of the plugin. However, the same cycle (as you can see, it is exactly the same code, since I use macros) for the "derived" type leads to a proper disposal of the object, but not to unloading of the plugin.

I think this represents a bug in GTypeModule. If not, I'd appreciate some pointers on how to workaround/solve this problem.
Comment 1 Ronald Bultje 2006-08-06 22:33:44 UTC
Created attachment 70343 [details]
app.c

gcc `pkg-config --libs --cflags glib-2.0 gmodule-2.0 gobject-2.0` -g -Wall -Werror -o app app.c
Comment 2 Ronald Bultje 2006-08-06 22:34:19 UTC
Created attachment 70344 [details]
mod.c

gcc `pkg-config --libs --cflags glib-2.0 gmodule-2.0 gobject-2.0` -g -Wall -Werror -shared -o libmod.so mod.c
Comment 3 Ronald Bultje 2006-08-06 22:38:15 UTC
Just to be clear, the output of this is:

$ ./app
Load
Parent init
parent dispose
Unload
Load
Parent init
Child init
Child dispose
parent dispose

The expected output is the very same thing, but with an 'Unload' at the end, to tell me that the plugin unloaded after the disposal of the instance of the derived type.

(glib 2.10.3, latest in Ubuntu Dapper 6.06)
Comment 4 Chris Wilson 2006-08-07 11:30:18 UTC
Seems to be a "trivial" leak:

--- gobject/gtype.c     2006-08-07 12:27:39.000000000 +0100
+++ gobject/,gtype.c    2006-08-07 12:27:34.000000000 +0100
@@ -2389,6 +2389,13 @@
        }
       
       type_class_init_Wm (node, pclass);
+
+      if (pclass)
+       {
+         G_WRITE_UNLOCK (&type_rw_lock);
+         g_type_class_unref (ptype);
+         G_WRITE_LOCK (&type_rw_lock);
+       }
     }
   G_WRITE_UNLOCK (&type_rw_lock);
   
Comment 5 Chris Wilson 2006-08-07 11:32:59 UTC
Though it helps if I post the right patch:

--- gobject/gtype.c     2006-08-07 12:31:53.000000000 +0100
+++ gobject/,gtype.c    2006-08-07 12:32:30.000000000 +0100
@@ -2389,6 +2389,13 @@
        }
       
       type_class_init_Wm (node, pclass);
+
+      if (pclass)
+       {
+         G_WRITE_UNLOCK (&type_rw_lock);
+         g_type_class_unref (pclass);
+         G_WRITE_LOCK (&type_rw_lock);
+       }
     }
   G_WRITE_UNLOCK (&type_rw_lock);
   
Comment 6 Owen Taylor 2006-08-07 11:40:23 UTC
But you can't unref the parent type while the child class is still in
use, can you? think about the normal pattern to "chain up".

In a quick look there does seem to be appropriate code to unref the parent type
at the end of type_data_last_unref_Wm(), though there might be something
off about the code in detail.
Comment 7 Chris Wilson 2006-08-07 12:16:26 UTC
Yes I was troubled....

For the first instance of the class a reference is taken to its parent class (and that indeed is the reference dropped by type_data_last_unref_Wm).

Inside type_class_init_Wm all data is copy from the parent class and no reference is taken (or required). I guessed that the class_ref here was just an instantiation purely so that class was complete for the copy and could be dropped immediately after.

No harm seems to come of adding that g_type_class_unref...

If it helps, I have this trace for ./app:
==23577== Object at 0x8050090 [GType::Parent, size 40], references 1 [++2, 1--].
==23577== Referenced 2 times, suppressed 0 ...
==23577== Created at:
==23577==    at 0x40425DE: type_data_make_W (gtype.c:1026)
==23577==    by 0x4042D7C: type_data_ref_Wm (gtype.c:1090)
==23577==    by 0x4046A76: g_type_class_ref (gtype.c:1074)
==23577==    by 0x402CFE1: g_object_newv (gobject.c:835)
==23577==    by 0x402D39E: g_object_new_valist (gobject.c:962)
==23577==    by 0x402D54F: g_object_new (gobject.c:800)
==23577==    by 0x8048C83: main (app.c:71)
==23577== ---
==23577== Referenced 1x:
==23577==    at 0x40469BA: g_type_class_ref (gtype.c:1100)
==23577==    by 0x4047111: g_type_class_ref (gtype.c:2404)
==23577==    by 0x402CFE1: g_object_newv (gobject.c:835)
==23577==    by 0x402D39E: g_object_new_valist (gobject.c:962)
==23577==    by 0x402D54F: g_object_new (gobject.c:800)
==23577==    by 0x8048C83: main (app.c:71)
==23577== ---
==23577== Unreferenced 1 times, suppressed 0 ...
==23577== Unreferenced 1x:
==23577==    at 0x40458AF: type_data_last_unref_Wm (gtype.c:1110)
==23577==    by 0x40463EB: g_type_class_unref (gtype.c:1122)
==23577==    by 0x404655A: g_type_free_instance (gtype.c:1621)
==23577==    by 0x4029495: g_object_unref (gobject.c:1797)
==23577==    by 0x8048CC8: main (app.c:74)
==23577== ---
which prompted the patch.
Comment 8 Ronald Bultje 2007-04-09 13:12:23 UTC
I just looked into this, and I think Chris is right. g_type_class_ref() takes a ref to pclass with which it sets up the derived class (type_class_init_Wm()), but it never unrefs it. This is not the same reference as the one that each type has to its parent (for chaining up, as Owen mentions), which is taken in type_data_ref_Wm(), not in g_type_class_ref() directly. Given this, Chris' patch looks to be correct to me.

Owen, could this patch be considered for applying? (And thanks for looking at this, Chris!)
Comment 9 Ronald Bultje 2007-05-24 13:24:07 UTC
OK, so actually some more info. I've been running with this, and it generally works fine. I've seen one problem, and would like some comment on it. Once over the past month, I've seen the following g_error() be triggered, implying a race condition in type registration / freeing for GTypeModule-associated GTypes:

GLib-GObject-ERROR **: g_type_plugin_*(0x25fb1c0) invalidly modified type `<name of my type>'

I've been able to trigger this experimentally in a setup where I run 2 threads, each of which has the capability to load/unload a certain module. Is GTypeModule threadsafe?

(Backtrace is being worked on...)
Comment 10 Ronald Bultje 2007-05-25 13:34:11 UTC
And just now I want to, it won't reproduce under my test conditions anymore. I was using an old glib when I was having those issues (and could reproduce it) and currently svn, would that make a difference? Any patch that would've addressed it?

Sorry for the spam et al, just trying to be helpful. :-).
Comment 11 Ronald Bultje 2008-02-01 17:30:49 UTC
Ping? This bug is 1 1/2 year old and has a tested patch, please do something. :-).
Comment 12 Matthias Clasen 2008-11-29 03:27:44 UTC
Tim, can I get you to say yes or no to the patch ?
Comment 13 Ronald Bultje 2009-04-12 21:54:33 UTC
Ping, 2 1/2 years now...
Comment 14 Jannis Pohlmann 2009-06-15 14:47:37 UTC
I'm having a similar or maybe even the same problem. I have an application with two plugins registering types dynamically. The application itself runs two or more threads. These threads create objects of the dynamically registered types quite often. I'd expect to be able to do that but it seems to cause race conditions inside GObject.

Sometimes I get the "invalidly modified type" error described above and sometimes I get this:

GLib-GObject:ERROR:gtype.c:1135:type_data_ref_Wm: assertion failed: (node->data->common.ref_count > 0)

Here's a backtrace for this (without GLib line numbers unfortunately):

  • #0 __kernel_vsyscall
  • #1 raise
    from /lib/libc.so.6
  • #2 abort
    from /lib/libc.so.6
  • #3 g_assertion_message
    from /usr/lib/libglib-2.0.so.0
  • #4 g_assertion_message_expr
    from /usr/lib/libglib-2.0.so.0
  • #5 g_type_class_ref
    from /usr/lib/libgobject-2.0.so.0
  • #6 g_object_newv
    from /usr/lib/libgobject-2.0.so.0
  • #7 g_object_new_valist
    from /usr/lib/libgobject-2.0.so.0
  • #8 g_object_new
    from /usr/lib/libgobject-2.0.so.0
  • #9 tumbler_provider_factory_get_providers
    at tumbler-provider-factory.c line 286
  • #10 tumbler_file_info_load
    at tumbler-file-info.c line 279
  • #11 tumbler_threshold_scheduler_thread
    at tumbler-threshold-scheduler.c line 402
  • #12 g_thread_pool_thread_proxy
    from /usr/lib/libglib-2.0.so.0
  • #13 g_thread_create_proxy
    from /usr/lib/libglib-2.0.so.0
  • #14 start_thread
    from /lib/libpthread.so.0
  • #15 clone
    from /lib/libc.so.6

Comment 15 Jannis Pohlmann 2009-06-15 15:17:36 UTC
The suggested patch doesn't solve the "node->data->common.ref_count > 0" error. Just tested it. Is it a different issue then?
Comment 16 Ronald Bultje 2009-06-15 15:24:47 UTC
The patch fixes a different issue. The warning I gave above is something I saw once while testing the patch - similar conditions as you. You're basically confirming that my patch is not the cause of the issue, which is what I sort-of thought already.

Speaking of... Can we get this patch in please? It's been sooooo long.
Comment 17 Tim Janik 2009-10-14 12:59:26 UTC
(In reply to comment #6)
> But you can't unref the parent type while the child class is still in
> use, can you? think about the normal pattern to "chain up".

This is right, parent classes need to stay referenced while children exist.

> In a quick look there does seem to be appropriate code to unref the parent type
> at the end of type_data_last_unref_Wm(), though there might be something
> off about the code in detail.

Correct, this is however the reference count acquired by
  type_data_ref_Wm(): if (pnode) type_data_ref_Wm (pnode);

(In reply to comment #8)
> I just looked into this, and I think Chris is right. g_type_class_ref() takes a
> ref to pclass with which it sets up the derived class (type_class_init_Wm()),
> but it never unrefs it.

Yes, thanks for spotting. The patch I'm going to attach fixes this.

(In reply to comment #9)
> I've been able to trigger this experimentally in a setup where I run 2 threads,
> each of which has the capability to load/unload a certain module. Is
> GTypeModule threadsafe?

We have had quite some threadsafety fixes in the past 24 months in the obejct/type system, so very likely you have been hitting another bug with your setup.
Comment 18 Tim Janik 2009-10-14 13:01:39 UTC
Created attachment 145419 [details] [review]
Fix parent class leak during derived class initialization

This is a slightly improved version of Chris' original fix.
Cody, could you please take care of testing this patch with the provided test cases and applying it?
Comment 19 Cody Russell 2009-10-15 02:27:00 UTC
Pushed as 8eebc189440693922e23298a761189cfbe71f796
Comment 20 Cody Russell 2009-10-15 02:27:37 UTC
Comment on attachment 145419 [details] [review]
Fix parent class leak during derived class initialization

Pushed as 8eebc189440693922e23298a761189cfbe71f796