glib creates thread-local data in init function, causing a crash if the lib is dlclose()d
Submitted by Rodger Combs
Link to original bug (#791462)
Description
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.dylib
g_private_get_impl + 71 frame #2 (closed): 0x000000010c880f3a libglib-2.0.0.dylibg_private_get + 9 frame #3: 0x000000010c85d137 libglib-2.0.0.dylib
thread_memory_from_self + 37 frame #4 (closed): 0x000000010c85cbb0 libglib-2.0.0.dylibg_slice_alloc + 25 frame #5: 0x000000010c836c8e libglib-2.0.0.dylib
g_hash_table_new_full + 36 frame #6 (closed): 0x000000010c852768 libglib-2.0.0.dylibg_quark_init + 32 frame #7: 0x00000001017b8a0a dyld
ImageLoaderMachO::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.
Recommended solution:
- 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.
Version: 2.54.x