+2014-11-05 Corinna Vinschen <corinna@vinschen.de>
+
+ * Makefile.in (NEW_FUNCTIONS): Add atexit to be not exported.
+ * lib/atexit.c (atexit): New, statically linkable version of atexit.
+ * dcrt0.cc (cygwin_atexit): Add comment to mark this function as old
+ entry point. Indiscriminately check for DSO of function pointer for
+ all functions, if checking for DSO of return address fails on x86_64.
+ Change comment accordingly.
+
2014-11-05 Corinna Vinschen <corinna@vinschen.de>
* Makefile.in (NEW_FUNCTIONS): Define target-independent. Add target
return __cxa_atexit (fn, obj, dso_handle);
}
+/* This function is only called for applications built with Cygwin versions
+ up to 1.7.32. Starting with 1.7.33, atexit is a statically linked function
+ inside of libcygwin.a. The reason is that the old method to fetch the
+ caller return address is unreliable given GCCs ability to perform tail call
+ elimination. For the details, see the below comment.
+ The atexit replacement is defined in libcygwin.a to allow reliable access
+ to the correct DSO handle. */
extern "C" int
cygwin_atexit (void (*fn) (void))
{
#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
+ Due to GCC's tail call 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
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;
- }
+ This also occurs for other functions.
+
+ Workaround: If dlls.find fails, try to find the dll entry of the DLL
+ containing fn. If that works, proceed by calling __cxa_atexit, otherwise
+ call atexit.
+
+ This *should* be sufficiently safe. Ultimately, new applications will
+ use the statically linked atexit function though, as outlined above. */
+ if (!d)
+ d = dlls.find ((void *) fn);
#endif
res = d ? __cxa_atexit ((void (*) (void *)) fn, NULL, d->handle) : atexit (fn);
return res;
--- /dev/null
+/* atexit.c: atexit entry point
+
+ Copyright 2014 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include <stddef.h>
+
+/* Statically linked replacement for the former cygwin_atexit. We need
+ the function here to be able to access the correct __dso_handle of the
+ caller's DSO. */
+int
+atexit (void (*fn) (void))
+{
+ extern int __cxa_atexit(void (*)(void*), void*, void*);
+ extern void *__dso_handle;
+
+ return __cxa_atexit ((void (*)(void*))fn, NULL, &__dso_handle);
+}