glib creates thread-local data in init function, causing a crash if the lib is dlclose()d
Submitted by Rodger Combs
The glib_init constructor function indirectly creates a thread-specific data key, as shown here:
- frame #0: 0x00007fff6d7a5a15 libsystem_pthread.dylib
pthread_key_create frame #1: 0x000000010c880f8a libglib-2.0.0.dylibg_private_get_impl + 71 frame #2 (closed): 0x000000010c880f3a libglib-2.0.0.dylib
g_private_get + 9 frame #3: 0x000000010c85d137 libglib-2.0.0.dylibthread_memory_from_self + 37 frame #4: 0x000000010c85cbb0 libglib-2.0.0.dylib
g_slice_alloc + 25 frame #5: 0x000000010c836c8e libglib-2.0.0.dylibg_hash_table_new_full + 36 frame #6: 0x000000010c852768 libglib-2.0.0.dylib
g_quark_init + 32 frame #7: 0x00000001017b8a0a dyldImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 420
(presumably missing stack frames for glib_init and glib_init_ctor due to optimizations)
This creates a problem if glib is loaded using dlopen(), and later closed using dlclose(). It would be fairly unusual to do so directly, but I ran into it when dlopen()ing and later dlclose()ing a library which depends on glib, which in turn opens and closes glib itself. Since glib is no longer mapped, the destructor function for the thread-specific key no longer exists, and the process crashes when the thread exits and its TSS keys are cleaned up.
Additionally, glib's constructor function appears to allocate data that is not freed when the lib is unloaded, which means that opening and closing the library leaks memory.
- During the library constructor, either free any thread-specific data allocated after finished with it, or don't use any to begin with.
- Add a destructor that frees any data allocated in the constructor.