* 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:
		| @@ -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> | 2009-08-12  Corinna Vinschen  <corinna@vinschen.de> | ||||||
|  |  | ||||||
| 	* fhandler_socket.cc (fhandler_socket::accept): Always use local | 	* fhandler_socket.cc (fhandler_socket::accept): Always use local | ||||||
|   | |||||||
| @@ -87,7 +87,10 @@ __cxa_guard_release () | |||||||
| } | } | ||||||
|  |  | ||||||
| /* These routines are made available as last-resort fallbacks | /* 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 = | struct per_process_cxx_malloc default_cygwin_cxx_malloc = | ||||||
| { | { | ||||||
|   | |||||||
| @@ -93,7 +93,28 @@ dlopen (const char *name, int) | |||||||
| 	  wchar_t *path = tp.w_get (); | 	  wchar_t *path = tp.w_get (); | ||||||
|  |  | ||||||
| 	  pc.get_wide_win32_path (path); | 	  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); | 	  ret = (void *) LoadLibraryW (path); | ||||||
|  |  | ||||||
|  | 	  /* Restore original cxx_malloc pointer. */ | ||||||
|  | 	  __cygwin_user_data.cxx_malloc = tmp_malloc; | ||||||
|  |  | ||||||
| 	  if (ret == NULL) | 	  if (ret == NULL) | ||||||
| 	    __seterrno (); | 	    __seterrno (); | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -328,6 +328,26 @@ dll_dllcrt0_1 (VOID *x) | |||||||
|  |  | ||||||
|   bool linked = !in_forkee && !cygwin_finished_initializing; |   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. */ |   /* Partially initialize Cygwin guts for non-cygwin apps. */ | ||||||
|   if (dynamically_loaded && user_data->magic_biscuit == 0) |   if (dynamically_loaded && user_data->magic_biscuit == 0) | ||||||
|     dll_crt0 (p); |     dll_crt0 (p); | ||||||
|   | |||||||
| @@ -33,6 +33,7 @@ CDECL_END								      \ | |||||||
| static HINSTANCE storedHandle;						      \ | static HINSTANCE storedHandle;						      \ | ||||||
| static DWORD storedReason;						      \ | static DWORD storedReason;						      \ | ||||||
| static void* storedPtr;							      \ | static void* storedPtr;							      \ | ||||||
|  | int __dynamically_loaded;						      \ | ||||||
| 									      \ | 									      \ | ||||||
| static int __dllMain (int a, char **b, char **c)			      \ | 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;							      \ |       storedHandle = h;							      \ | ||||||
|       storedReason = reason;						      \ |       storedReason = reason;						      \ | ||||||
|       storedPtr = ptr;							      \ |       storedPtr = ptr;							      \ | ||||||
|  |       __dynamically_loaded = (ptr == NULL);				      \ | ||||||
|       dll_index = cygwin_attach_dll (h, &__dllMain);			      \ |       dll_index = cygwin_attach_dll (h, &__dllMain);			      \ | ||||||
|       if (dll_index == (DWORD) -1)					      \ |       if (dll_index == (DWORD) -1)					      \ | ||||||
| 	ret = 0;							      \ | 	ret = 0;							      \ | ||||||
|   | |||||||
| @@ -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.  */ | /* Avoid an info message from linker when linking applications.  */ | ||||||
| extern __declspec(dllimport) struct _reent *_impure_ptr; | extern __declspec(dllimport) struct _reent *_impure_ptr; | ||||||
|  |  | ||||||
|  | /* Initialised in _cygwin_dll_entry. */ | ||||||
|  | extern int __dynamically_loaded; | ||||||
|  |  | ||||||
| #undef environ | #undef environ | ||||||
|  |  | ||||||
| extern "C" | extern "C" | ||||||
| @@ -70,11 +73,13 @@ _cygwin_crt0_common (MainFunc f, per_process *u) | |||||||
|   per_process *newu = (per_process *) cygwin_internal (CW_USER_DATA); |   per_process *newu = (per_process *) cygwin_internal (CW_USER_DATA); | ||||||
|   int uwasnull; |   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) |   if (u != NULL) | ||||||
|     uwasnull = 0;	/* Caller allocated space for per_process structure.  */ |     uwasnull = 0;	/* Caller allocated space for per_process structure.  */ | ||||||
|   else |   else | ||||||
|     { |     { | ||||||
|       u = newu;	/* Using DLL built-in per_process.  */ |       u = newu;		/* Using DLL built-in per_process.  */ | ||||||
|       uwasnull = 1;	/* Remember for later.  */ |       uwasnull = 1;	/* Remember for later.  */ | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -114,8 +119,10 @@ _cygwin_crt0_common (MainFunc f, per_process *u) | |||||||
|   u->realloc = &realloc; |   u->realloc = &realloc; | ||||||
|   u->calloc = &calloc; |   u->calloc = &calloc; | ||||||
|  |  | ||||||
|   /* Likewise for the C++ memory operators - if any.  */ |   /* Likewise for the C++ memory operators, if any, but not if we | ||||||
|   if (newu && newu->cxx_malloc) |      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.  */ |       /* Inherit what we don't override.  */ | ||||||
| #define CONDITIONALLY_OVERRIDE(MEMBER) \ | #define CONDITIONALLY_OVERRIDE(MEMBER) \ | ||||||
| @@ -129,12 +136,10 @@ _cygwin_crt0_common (MainFunc f, per_process *u) | |||||||
|       CONDITIONALLY_OVERRIDE(oper_new___nt); |       CONDITIONALLY_OVERRIDE(oper_new___nt); | ||||||
|       CONDITIONALLY_OVERRIDE(oper_delete_nt); |       CONDITIONALLY_OVERRIDE(oper_delete_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.  */ |   /* Setup the module handle so fork can get the path name.  */ | ||||||
|   u->hmodule = GetModuleHandle (0); |   u->hmodule = GetModuleHandle (0); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user