* 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.
This commit is contained in:
Corinna Vinschen 2009-08-13 07:35:50 +00:00
parent 61189f19de
commit ce5eb135a2
6 changed files with 70 additions and 8 deletions

View File

@ -1,3 +1,14 @@
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

View File

@ -87,7 +87,10 @@ __cxa_guard_release ()
}
/* 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 =
{

View File

@ -93,7 +93,28 @@ dlopen (const char *name, int)
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 ();
}

View File

@ -328,6 +328,26 @@ dll_dllcrt0_1 (VOID *x)
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);

View File

@ -33,6 +33,7 @@ CDECL_END \
static HINSTANCE storedHandle; \
static DWORD storedReason; \
static void* storedPtr; \
int __dynamically_loaded; \
\
static int __dllMain (int a, char **b, char **c) \
{ \
@ -53,6 +54,7 @@ int WINAPI _cygwin_dll_entry (HINSTANCE h, DWORD reason, void *ptr) \
storedHandle = h; \
storedReason = reason; \
storedPtr = ptr; \
__dynamically_loaded = (ptr == NULL); \
dll_index = cygwin_attach_dll (h, &__dllMain); \
if (dll_index == (DWORD) -1) \
ret = 0; \

View File

@ -40,6 +40,9 @@ extern WEAK void operator delete[](void *p, const std::nothrow_t &nt) throw()
/* 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"
@ -70,11 +73,13 @@ _cygwin_crt0_common (MainFunc f, per_process *u)
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. */
}
@ -114,8 +119,10 @@ _cygwin_crt0_common (MainFunc f, per_process *u)
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) \
@ -129,12 +136,10 @@ _cygwin_crt0_common (MainFunc f, per_process *u)
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);