Created attachment 8223 [details]
Tickle dlerror from multiple threads
__dlerror and _dlerror_run in dlfcn.h will use a shared, static buffer if pthreads is not present when initializing internal state. And they continue using the shared buffer even after pthreads is loaded. This can result in double frees, NULL pointer dereferences, and other fun.
I ran into this bug via a Lua module. No Lua interpreter shipped on a major distribution links the interpreter against libpthread.so. However, there are many Lua modules which use pthreads and cause libpthread to be linked in via dlopen. If dlopen/dlclose are used from multiple threads (e.g. spinning up new Lua VMs in the threads, which will then load modules), then you can trigger this bug. You're much more likely to encounter problems if the threads are short-lived and the Lua interpreters unload their modules via dlclose, or if they try to load non-existent modules.
Attached is a simple proof of concept in plain C. It loads libpthread using dlopen("libpthread.so.0", RTLD_GLOBAL), spins up multiple threads, and from each thread tickles dlerror by repeatedly attempting to open non-existent libraries.
Note that Lua modules are usually loaded RTLD_LOCAL, so that might complicate any solution.
FWIW, strsignal.c has this same problem. where_is_shmfs in shm_open.c also has an initialization race. gaiconf_init in getaddrinfo.c might be subject to a race, but I couldn't quickly determine which globals it accesses.