dlclosing libxml2 with threads crashes
Hello,
Here is a horror story... libtest.c and test-xml.c is a reproducer for crashing. Run
gcc libtest.c -o libtest.so -shared -fPIC $(xml2-config --cflags) $(xml2-config --libs) -Wall
gcc test-xml.c -o test -lpthread -ldl
LD_LIBRARY_PATH=. ./test
and that will crash. What happens is:
- the main thread
dlopen()s
libtest.so and makes it use xml. - libxml2's
xmlOnceInit()
thus callspthread_key_create()
, to store per-thread xml state, and passes thexmlFreeGlobalState
destructor function. - we create another thread
- the other thread
dlopen()s
libtest.so as well and makes it use xml too. That triggers a call toxmlGetGlobalState()
which allocates the per-thread xml state - the other thread
dlclose()s
libtest.so, but it remains loaded, and per-thread xml state remains allocated. - the main thread
dlclose()s
libtest.so too - that triggers an actual
dlclose()
of libxml - the other thread terminates
- the thread library tries to call the per-thread key destructor
xmlFreeGlobalState()
but that's not loaded any more... - thus a segfault...
The real problem here is that libxml2 doesn't get to call pthread_key_delete()
to unregister its destructor function. There is the xmlCleanupThreads()
function which is meant to get it to call pthread_key_delete()
, but also a lot of other xml stuff, and thus it's very unsafe since it's very hard to know whether libxml2 is to be unloaded or not (think concurrent threads doing whatever else, here I showed an example of loading a plugin to make it do some stuff, this is a situation I have actually encountered with hwloc + OpenMPI + Fortran).
Perhaps we could just add an ELF destructor that calls xmlCleanupThreads()
, as this patch does?
This does fix my testcase, and does make sense to me. It just needs to be enabled only on platforms which are not choking on the destructor
attribute.
Samuel