[PATCH] dlfcn: Fix dlclose crash during C++ thread_local destructor (BZ 33598)
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Fri Dec 12 16:02:01 GMT 2025
On 10/12/25 08:30, Arjun Shankar wrote:
> Hi Adhemerval,
>
> It looks like this won't work if the library getting unmapped doesn't
> directly call dlclose, and instead there's a level of indirection,
> like so:
>
> cat <<EOF > main.c
> #include <dlfcn.h>
> #include <assert.h>
> int main()
> {
> void *h = dlopen("lib1.so", RTLD_NOW); assert(h);
> dlclose(h);
> return 0;
> }
> EOF
> cat <<EOF > lib1.cc
> #include <dlfcn.h>
> #include <assert.h>
> #include <memory>
> thread_local std::unique_ptr<int> tlp;
> static struct c1 {
> void *h;
> void (*init)(void);
> void (*cleanup)(void);
> c1() {
> h = dlopen("lib2.so", RTLD_NOW); assert(h);
> init = (void (*)(void)) dlsym(h, "init"); assert(init);
> cleanup = (void (*)(void)) dlsym(h, "cleanup"); assert(cleanup);
> init();
> tlp = std::make_unique<int>();
> }
> ~c1() { cleanup(); dlclose(h); }
> } c1;
> EOF
> cat <<EOF > lib2.c
> #include <dlfcn.h>
> #include <assert.h>
> static void *h;
> void init(void) { h = dlopen("libm.so.6", RTLD_NOW); assert(h); }
> void cleanup(void) { dlclose(h); }
> EOF
> gcc -Wall -g -fPIC -shared -o lib2.so lib2.c -ldl
> g++ -Wall -g -fPIC -shared -o lib1.so lib1.cc -ldl
> gcc -Wall -g -fPIC -o main main.c -ldl
> LD_LIBRARY_PATH=. ./main
>
> Can this be tackled more generally by deferring or not unmapping
> during program exit?
>
Interesting enough I adapted these testcase to glibc along with my patch
and although it works on x86_64 and aarch64, it does fail on i686 (the
___dclose passes the lib2.c for the RETURN_ADDRESS, which x86 and aarch64
the lib1.c).
And I though initially in using a more strict way to just making dlclose
no-op during exit; and now I think it would be easiest solution indeed.
I think it is highly unlikely that a DSO/TLS destructor or an atexit/etc
would rely on dlclose to unmap the object.
More information about the Libc-alpha
mailing list