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 374940 - GType system should be completely unloadable
GType system should be completely unloadable
Status: RESOLVED WONTFIX
Product: glib
Classification: Platform
Component: gobject
2.23.x
Other All
: Normal critical
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2006-11-14 01:20 UTC by Christian Grothoff
Modified: 2011-02-18 16:14 UTC
See Also:
GNOME target: ---
GNOME version: ---



Description Christian Grothoff 2006-11-14 01:20:32 UTC
Suppose you have the following architecture:

1) A main (glib-based) application, which uses
2) A pure C library (no glib) which supports plugins, such as
3) A plugin which uses libgsf

Note that the C library is NOT linked against glib
and does not use Gmodule (say, it uses libltdl from
libtool instead) and does not have any understanding 
of GTypes.  Also, the C library encapsulates its 
plugins.  Furthermore, the main application does
NOT know about libgsf (does not need it, does not
link against it, does not want to be aware of it).


Then the following can happen:

a) main program initializes type syste calls C library
b) C library loads plugin; plugin is dynamically linked
   against libgsf; libgsf's glib dependencies are 
   resolved against the glib of the main program, 
   sharing glib's type system
c) libgsf registers libgsf specific types with glib
d) plugin uses libgsf; everything is fine
e) plugin is unloaded, libgsf is removed from memory
   (no longer needed), but, and this is the BUG,
   its types are still registered with gobject
   (and this is no easy fix; while we can have a
   destructor (fini-function) in libgsf, there seems
   to be no good mechanism for unregistering types
   from libgobject)
f) later, plugin is needed again, loaded again,
   libgsf is again resolved against existing glib
g) libgsf tries to register its types with glib,
   but since types of those names (!) already exist,
   gobject refuses (!) 
h) libgsf object creation fails, CRASH.


Workaround: link everything against libgsf, break modularity,
waste memory.  

Fixes: 
a1) allow deregistration of statically registered types in gobject
a2) have proper libgsf cleanup that does a)
b) have libgsf use dynamic registration (much harder to get
   right, but maybe easier to do than a1+a2)
c) have proper class loader mechanism in libgobject


This bug probably exists in tons of glib-based libraries.
A testcase (with full autotools build) is available at

https://gnunet.org/svn/bugGSF/
Comment 1 Jon Kåre Hellan 2006-11-14 13:18:11 UTC
The abiword people have been discussing this problem. CC-ing Dom.
Comment 2 Dominic Lachowicz 2006-11-14 14:21:32 UTC
I ran into this problem with librsvg. There's not much (if anything) that libgsf can do here - this is a fundamental brokenness in gobject's type registration system that affect all gobject subclasses. See also bug 357406 and bug 362217 and http://mail.gnome.org/archives/desktop-devel-list/2006-November/msg00009.html
Comment 3 Matthias Clasen 2006-11-15 18:33:42 UTC
Not brokenness, but a well-known and documented limitation.

a1) allow deregistration of statically registered types in gobject

Thats nonsensical. The very point of _static_ registration is that
it is, well, static

b) have libgsf use dynamic registration (much harder to get
   right, but maybe easier to do than a1+a2)

thats the way to go if you need dynamic registration, yes

c) have proper class loader mechanism in libgobject

not totally clear what that means, apart from using dynamic registration
everywhere.

Comment 4 Behdad Esfahbod 2006-11-15 20:06:53 UTC
The problem here is very clear and can happen with /any/ library defining GTypes.    I don't know what the proper solution is, but atexit() may be useful, since on glibc, it can be used to schedule a function to be called when a shared library is being unloaded.
Comment 5 Tor Lillqvist 2006-11-15 21:09:52 UTC
I would strongly recommend against relying on atexit(). Its exact semantics when called from shared objects varies wildly from platform to platform.
Comment 6 Christian Grothoff 2007-07-03 00:04:13 UTC
Matthias Clasen wrote:
> Not brokenness, but a well-known and documented limitation.

Well, if a limitation is so severe that it means that certain things, which people want to do for good reasons, are impossible, I'd call it broken.

> a1) allow deregistration of statically registered types in gobject
>
> Thats nonsensical. The very point of _static_ registration is that
> it is, well, static

I understand that.  However, dynamic registration is broken (see below), and the way to fix it maybe to get rid of static registration and say that all registration is dynamic in some sense (as in, can be un-done), keeping the broken dynamic registration bit only for the case where it actually works.

> b) have libgsf use dynamic registration (much harder to get
>    right, but maybe easier to do than a1+a2)
>
> thats the way to go if you need dynamic registration, yes

Here is the issue with dynamic registration that I might not have been clear  enough about:  You can only use dynamic registration if you already HAVE a type registered.  So to bootstrap the entire thing, you need static registration (to register the types that are required for dynamic registration).  Now, if you are writing a plugin (where *everything* must be unloaded) and you cannot rely on anything to pre-exist (no static types available outside of the plugin), you cannot use the existing dynamic registration mechanism.  

I hope this helps.
Comment 7 Matthias Clasen 2007-07-03 16:05:58 UTC
> Well, if a limitation is so severe that it means that certain things, which
> people want to do for good reasons, are impossible, I'd call it broken.

"limitation" kind of implies "certain things are not possible". Otherwise it would not be a limitation...

> You can only use dynamic registration if you already HAVE a type
> registered. 

Not entirely clear what you mean here ? Are you talking about basic gobject types that you need to derive your dynamic types from ? 
Comment 8 Christian Grothoff 2007-07-03 17:22:54 UTC
I'm talking about how to get a "GTypePlugin" instance in the first place.
Comment 9 Andrés G. Aragoneses (IRC: knocte) 2009-12-02 17:15:44 UTC
ping? Any more feedback is appreciated.

BTW, I was thinking about a new alternative solution besides a,b,c:

d) simply ignore re-registration of already-registered types, to make gobject not refuse at (g), so as the crash in (h) doesn't happen.

Is that feasible?

Thanks.
Comment 10 Javier Jardón (IRC: jjardon) 2009-12-02 19:16:39 UTC
Upgrade the latest affected glib version
Comment 11 Sven Herzberg 2010-01-13 12:42:08 UTC
IMHO, this is a bug in the module linking against libgsf.

Glib has the limitation Matthias pointed out for some reason IIRC. So, if your plugin needs to link against libgsf, you should make sure, that your plugin isn't unloadable again.

In the GTypePlugin use-case, one would call g_type_plugin_use() when registering the types. If you're using a different approach, you'll have to check how to do this with your plugin system.

IMHO, this is NOTABUG (because it is a well-known and well-documented limitation).

If people really consider that this should be fixed, this should not be critical, but an enhancement request only.

Comments?
Comment 12 Christian Grothoff 2010-01-13 13:53:22 UTC
Given Sven's comment and the persistence of the issue, I assume that the Glib developers have no interest in fixing this "limitation".  As a result, I have added out-of-process (fork, exec) execution support for plugins to GNU libextractor.  So now I *can* unload plugins that use Glib code (by killing processes).  For most plugins, this is optional (since it costs performance and should not be needed), but the Glib-based plugins are going to have the distinction of being out-of-process only until this issue is resolved.

I assume you think this is a good thing.

New Revision: 9987

Modified:
   Extractor/src/plugins/ole2_extractor.c
   Extractor/src/plugins/thumbnailgtk_extractor.c
Log:
Gnome thinks unloading plugins is an unnecessary feature, so we only run Gnome code out-of-process from now on

Modified: Extractor/src/plugins/ole2_extractor.c
===================================================================
--- Extractor/src/plugins/ole2_extractor.c      2010-01-13 13:46:37 UTC (rev 9986)
+++ Extractor/src/plugins/ole2_extractor.c      2010-01-13 13:52:34 UTC (rev 9987)
@@ -475,6 +475,21 @@
 }
 
 
+
+const char *
+EXTRACTOR_ole2_options ()
+{
+  /* 
+     Since the Gnome developers think that being unable to
+     unload plugins is an 'acceptable' limitation, we
+     require out-of-process execution for plugins depending
+     on libgsf and other glib-based plugins.
+     See also https://bugzilla.gnome.org/show_bug.cgi?id=374940 
+  */
+  return "oop-only"; 
+}
+
+
 int 
 EXTRACTOR_ole2_extract (const char *data,
                        size_t size,

Modified: Extractor/src/plugins/thumbnailgtk_extractor.c
===================================================================
--- Extractor/src/plugins/thumbnailgtk_extractor.c      2010-01-13 13:46:37 UTC (rev 9986)
+++ Extractor/src/plugins/thumbnailgtk_extractor.c      2010-01-13 13:52:34 UTC (rev 9987)
@@ -41,6 +41,20 @@
 }
 
 
+const char *
+EXTRACTOR_thumbnailgtk_options ()
+{
+  /* 
+     Since the Gnome developers think that being unable to
+     unload plugins is an 'acceptable' limitation, we
+     require out-of-process execution for plugins depending
+     on libgsf and other glib-based plugins.
+     See also https://bugzilla.gnome.org/show_bug.cgi?id=374940 
+  */
+  return "oop-only"; 
+}
+
+
Comment 13 André Klapper 2010-01-13 14:46:00 UTC
(In reply to comment #12)
> Gnome thinks unloading plugins is an unnecessary feature

Ah, so it's Mr. Gnome's fault, that evil person!
(/me tired of strange generalizations by people that disagree with other people)
Comment 14 Sven Herzberg 2010-01-15 13:57:50 UTC
Renaimg the bug to actually reflect the wishes of the bug reporter for future references.
Comment 15 Tim Janik 2010-01-15 15:32:31 UTC
(In reply to comment #0)
> e) plugin is unloaded, libgsf is removed from memory
>    (no longer needed), but, and this is the BUG,
>    its types are still registered with gobject
>    (and this is no easy fix; while we can have a
>    destructor (fini-function) in libgsf, there seems
>    to be no good mechanism for unregistering types
>    from libgobject)

Registered GType IDs cannot be unregistered by design.
There is no way to work around this intentional design decision, short of replacing the GObject type system (which is considerably unliekly to happen).
For you particular case, you could look into making all libgsf type fully dynamic and unloadable type implementations. This *is* supported by the type system.
The entirety of GType/GObject/GLib cannot be made unloadable however, so I'm closing this bug report (indiferent about wether people want to call this WONTFIX/NOTABUG/INVALID or whatever).
Comment 16 Christian Grothoff 2010-01-15 15:49:43 UTC
I agree that the way to fix this would be to replace the GObject type system. That was always what I was thinking was needed. 

libgsf cannot by itself be made unloadable without using at least one subtype of GTypePlugin that is static and hence the overall library would remain un-unloadable, so this is not a solution.

Clearly the overall point is that from a program that does not link itself against GLib calling 'dlopen'on *any* library that links against GLib implies that one can NEVER SAFELY call 'dlclose' on that library later.  The only solution is to fork() and use IPC if unloading is required or desired.