[PATCH v3] dlfcn: Fix dlclose crash in atexit handler after thread_local destructor (BZ 33598)

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Tue May 5 20:45:25 GMT 2026



On 05/05/26 16:36, Florian Weimer wrote:
> * Adhemerval Zanella:
> 
>> @@ -46,6 +47,9 @@ __run_exit_handlers (int status, struct exit_function_list **listp,
>>    /* The exit should never return, so there is no need to unlock it.  */
>>    __libc_lock_lock_recursive (__exit_lock);
>>  
>> +  /* Disable unmap objects through dlclose by TLS destructor (BZ 33598).  */
>> +  GL(dl_at_exit) = true;
>> +
>>    /* First, call the TLS destructors.  */
>>    if (run_dtors)
>>      call_function_static_weak (__call_tls_dtors);
>> diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
>> index 15c46598539..236419c593c 100644
>> --- a/sysdeps/generic/ldsodefs.h
>> +++ b/sysdeps/generic/ldsodefs.h
>> @@ -441,6 +441,9 @@ struct rtld_global
>>    /* Generation counter for the dtv.  */
>>    EXTERN size_t _dl_tls_generation;
>>  
>> +  /* Disable unmap objects during __run_exit_handlers.  */
>> +  EXTERN bool _dl_at_exit;
>> +
>>    /* Scopes to free after next THREAD_GSCOPE_WAIT ().  */
>>    EXTERN struct dl_scope_free_list
>>    {
> 
> Would it be simpler to do what the comment says?  Just guard the
> munmap call that is part of dlclose?  This could even be considered an
> optimization.

It should work, the main difference is with this approach (assume_in_use = false),
_dl_close_worker during exit marks every object IDX_STILL_USED and returns 
immediately, so fo finalizers run. The _dl_fini handles every library in its
own sorted pass later.

With the DL_UNMAP approach, _dl_close_worker runs normally and unloadable libraries
get their finalizers called by _dl_call_fini inside _dl_close_worker.

I think it makes sense to use your suggestion. I will send a new version.


More information about the Libc-alpha mailing list