* dll_init.cc (dll_dllcrt0_1): Likewise.
* dlfcn.cc (dlopen): Prevent dlopen()'d DLL from installing any
cxx malloc overrides.
* include/cygwin/cygwin_dll.h (__dynamically_loaded): New variable.
* lib/_cygwin_crt0_common.cc (_cygwin_crt0_common): Check it and only
install cxx malloc overrides when statically loaded. Extend comments.
+2009-08-13 Corinna Vinschen <corinna@vinschen.de>
+ Dave Korn <dave.korn.cygwin@googlemail.com>
+
+ * cxx.cc (default_cygwin_cxx_malloc): Enhance commenting.
+ * dll_init.cc (dll_dllcrt0_1): Likewise.
+ * dlfcn.cc (dlopen): Prevent dlopen()'d DLL from installing any
+ cxx malloc overrides.
+ * include/cygwin/cygwin_dll.h (__dynamically_loaded): New variable.
+ * lib/_cygwin_crt0_common.cc (_cygwin_crt0_common): Check it and only
+ install cxx malloc overrides when statically loaded. Extend comments.
+
2009-08-12 Corinna Vinschen <corinna@vinschen.de>
* fhandler_socket.cc (fhandler_socket::accept): Always use local
}
/* These routines are made available as last-resort fallbacks
- for the application. Should not be used in practice. */
+ for the application. Should not be used in practice; the
+ entries in this struct get overwritten by each DLL as it
+ is loaded, and libstdc++ will override the whole lot first
+ thing of all. */
struct per_process_cxx_malloc default_cygwin_cxx_malloc =
{
wchar_t *path = tp.w_get ();
pc.get_wide_win32_path (path);
+
+ /* Workaround for broken DLLs built against Cygwin versions 1.7.0-49
+ up to 1.7.0-57. They override the cxx_malloc pointer in their
+ DLL initialization code even if loaded dynamically. This is a
+ no-no since a later dlclose lets cxx_malloc point into nirvana.
+ The below kludge "fixes" that by reverting the original cxx_malloc
+ pointer after LoadLibrary. This implies that their overrides
+ won't be applied; that's OK. All overrides should be present at
+ final link time, as Windows doesn't allow undefined references;
+ it would actually be wrong for a dlopen'd DLL to opportunistically
+ override functions in a way that wasn't known then. We're not
+ going to try and reproduce the full ELF dynamic loader here! */
+
+ /* Store original cxx_malloc pointer. */
+ struct per_process_cxx_malloc *tmp_malloc;
+ tmp_malloc = __cygwin_user_data.cxx_malloc;
+
ret = (void *) LoadLibraryW (path);
+
+ /* Restore original cxx_malloc pointer. */
+ __cygwin_user_data.cxx_malloc = tmp_malloc;
+
if (ret == NULL)
__seterrno ();
}
bool linked = !in_forkee && !cygwin_finished_initializing;
+ /* Broken DLLs built against Cygwin versions 1.7.0-49 up to 1.7.0-57
+ override the cxx_malloc pointer in their DLL initialization code,
+ when loaded either statically or dynamically. Because this leaves
+ a stale pointer into demapped memory space if the DLL is unloaded
+ by a call to dlclose, we prevent this happening for dynamically
+ loaded DLLS in dlopen by saving and restoring cxx_malloc around
+ the call to LoadLibrary, which invokes the DLL's startup sequence.
+ Modern DLLs won't even attempt to override the pointer when loaded
+ statically, but will write their overrides directly into the
+ struct it points to. With all modern DLLs, this will remain the
+ default_cygwin_cxx_malloc struct in cxx.cc, but if any broken DLLs
+ are in the mix they will have overridden the pointer and subsequent
+ overrides will go into their embedded cxx_malloc structs. This is
+ almost certainly not a problem as they can never be unloaded, but
+ if we ever did want to do anything about it, we could check here to
+ see if the pointer had been altered in the early parts of the DLL's
+ startup, and if so copy back the new overrides and reset it here.
+ However, that's just a note for the record; at the moment, we can't
+ see any need to worry about this happening. */
+
/* Partially initialize Cygwin guts for non-cygwin apps. */
if (dynamically_loaded && user_data->magic_biscuit == 0)
dll_crt0 (p);
static HINSTANCE storedHandle; \
static DWORD storedReason; \
static void* storedPtr; \
+int __dynamically_loaded; \
\
static int __dllMain (int a, char **b, char **c) \
{ \
storedHandle = h; \
storedReason = reason; \
storedPtr = ptr; \
+ __dynamically_loaded = (ptr == NULL); \
dll_index = cygwin_attach_dll (h, &__dllMain); \
if (dll_index == (DWORD) -1) \
ret = 0; \
/* Avoid an info message from linker when linking applications. */
extern __declspec(dllimport) struct _reent *_impure_ptr;
+/* Initialised in _cygwin_dll_entry. */
+extern int __dynamically_loaded;
+
#undef environ
extern "C"
per_process *newu = (per_process *) cygwin_internal (CW_USER_DATA);
int uwasnull;
+ /* u is non-NULL if we are in a DLL, and NULL in the main exe.
+ newu is the Cygwin DLL's internal per_process and never NULL. */
if (u != NULL)
uwasnull = 0; /* Caller allocated space for per_process structure. */
else
{
- u = newu; /* Using DLL built-in per_process. */
+ u = newu; /* Using DLL built-in per_process. */
uwasnull = 1; /* Remember for later. */
}
u->realloc = &realloc;
u->calloc = &calloc;
- /* Likewise for the C++ memory operators - if any. */
- if (newu && newu->cxx_malloc)
+ /* Likewise for the C++ memory operators, if any, but not if we
+ were dlopen()'d, as we might get dlclose()'d and that would
+ leave stale function pointers behind. */
+ if (newu && newu->cxx_malloc && !__dynamically_loaded)
{
/* Inherit what we don't override. */
#define CONDITIONALLY_OVERRIDE(MEMBER) \
CONDITIONALLY_OVERRIDE(oper_new___nt);
CONDITIONALLY_OVERRIDE(oper_delete_nt);
CONDITIONALLY_OVERRIDE(oper_delete___nt);
+ /* Now update the resulting set into the global redirectors. */
+ *newu->cxx_malloc = __cygwin_cxx_malloc;
}
- /* Now update the resulting set into the global redirectors. */
- if (newu)
- newu->cxx_malloc = &__cygwin_cxx_malloc;
-
/* Setup the module handle so fork can get the path name. */
u->hmodule = GetModuleHandle (0);