Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--winsup/cygwin/ChangeLog5
-rw-r--r--winsup/cygwin/dcrt0.cc30
-rw-r--r--winsup/cygwin/release/1.7.333
3 files changed, 38 insertions, 0 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index bf6b00715..669f71237 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,10 @@
2014-10-27 Corinna Vinschen <corinna@vinschen.de>
+ * dcrt0.cc (cygwin_atexit): Add workaround for broken atexit calls
+ in __gcc_register_frame of DLLs built with gcc-4.8.3-3.
+
+2014-10-27 Corinna Vinschen <corinna@vinschen.de>
+
* dlfcn.cc (dlopen): Drop patch accommodating SetDllDiretory from
2014-10-14.
diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
index 930397f06..b2bbe8657 100644
--- a/winsup/cygwin/dcrt0.cc
+++ b/winsup/cygwin/dcrt0.cc
@@ -1236,7 +1236,37 @@ extern "C" int
cygwin_atexit (void (*fn) (void))
{
int res;
+
dll *d = dlls.find ((void *) _my_tls.retaddr ());
+#ifdef __x86_64__
+ /* x86_64 DLLs created with GCC 4.8.3-3 register __gcc_deregister_frame
+ as atexit function using a call to atexit, rather than __cxa_atexit.
+ Due to GCC's aggressive optimizing, cygwin_atexit doesn't get the correct
+ return address on the stack. As a result it fails to get the HMODULE of
+ the caller and thus calls atexit rather than __cxa_atexit. Then, if the
+ module gets dlclosed, __cxa_finalize (called from dll_list::detach) can't
+ remove __gcc_deregister_frame from the atexit function chain. So at
+ process exit, __call_exitprocs calls __gcc_deregister_frame while the
+ module is already unloaded and the __gcc_deregister_frame function not
+ available ==> SEGV.
+
+ Workaround: If dlls.find fails, and _my_tls.retaddr is a Cygwin function
+ address, and fn is a function address in another DLL, try to find the
+ dll entry of the DLL containing fn. Then check if fn is the address of
+ the DLLs __gcc_deregister_frame function. If so, proceed by calling
+ __cxa_atexit, otherwise call atexit. */
+ extern void *__image_base__;
+ if (!d
+ && (uintptr_t) _my_tls.retaddr () >= (uintptr_t) &__image_base__
+ && (uintptr_t) _my_tls.retaddr () <= (uintptr_t) &_cygheap_start
+ && (uintptr_t) fn > (uintptr_t) &_cygheap_start)
+ {
+ d = dlls.find ((void *) fn);
+ if (d && (void *) GetProcAddress (d->handle, "__gcc_deregister_frame")
+ != fn)
+ d = NULL;
+ }
+#endif
res = d ? __cxa_atexit ((void (*) (void *)) fn, NULL, d->handle) : atexit (fn);
return res;
}
diff --git a/winsup/cygwin/release/1.7.33 b/winsup/cygwin/release/1.7.33
index c7acd071d..13d278648 100644
--- a/winsup/cygwin/release/1.7.33
+++ b/winsup/cygwin/release/1.7.33
@@ -83,3 +83,6 @@ Bug Fixes
- Fix a SEGV in cygcheck if the environment variable COMSPEC is not, or
incorrectly set.
Addresses: https://cygwin.com/ml/cygwin/2014-10/msg00292.html
+
+- Fix a SEGV in some 64 bit applications explicitely dlclosing DLLs.
+ Addresses: https://cygwin.com/ml/cygwin/2014-10/msg00402.html