https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=1b1f0d8b32c748dd2bca130d6f66b1c2dff52a48
commit 1b1f0d8b32c748dd2bca130d6f66b1c2dff52a48 Author: Takashi Yano <[email protected]> Date: Tue Oct 28 09:30:41 2025 +0900 Cygwin: dll_init: Always call __cxa_finalize() for DLL_LOAD For dlopen()'ed DLL, __cxa_finalize() should always be called at dll detach time. The reason is as follows. In the case that dlopen()'ed DLL A is dlclose()'ed in the destructor of DLL B, and the destructor of DLL B is called in exit_state, DLL A will be unloaded by dlclose(). If __cxa_finalize() for DLL A is not called here, the destructor of DLL A will be called in exit() even though DLL A is already unloaded. This causes crash at exit(). In this case, __cxa_finalize() should be called before unloading DLL A even in exit_state. Addresses: https://cygwin.com/pipermail/cygwin/2025-October/258877.html Fixes: c019a66c32f8 ("* dll_init.cc (dll_list::detach) ... Don't call __cxa_finalize in exiting case.") Reported-by: Thomas Huth <[email protected]> Reviewed-by: Mark Geisert <[email protected]>, Jon Turney <[email protected]>, Corinna Vinschen <[email protected]> Signed-off-by: Takashi Yano <[email protected]> (cherry picked from commit 0d2f981940a496a41b0b650a4ba286d9137302f7) Diff: --- winsup/cygwin/dll_init.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc index 1369165c9..d2ed74bed 100644 --- a/winsup/cygwin/dll_init.cc +++ b/winsup/cygwin/dll_init.cc @@ -584,7 +584,16 @@ dll_list::detach (void *retaddr) /* Ensure our exception handler is enabled for destructors */ exception protect; /* Call finalize function if we are not already exiting */ - if (!exit_state) + /* For dlopen()'ed DLL, __cxa_finalize() should always be called + at dll detach time. The reason is as follows. In the case that + dlopen()'ed DLL A is dlclose()'ed in the destructor of DLL B, + and the destructor of DLL B is called in exit_state, DLL A will + be unloaded by dlclose(). If __cxa_finalize() for DLL A is not + called here, the destructor of DLL A will be called in exit() + even though DLL A is already unloaded. This causes crash at + exit(). In this case, __cxa_finalize() should be called before + unloading DLL A even in exit_state. */ + if (!exit_state || d->type == DLL_LOAD) __cxa_finalize (d->handle); d->run_dtors (); }
