* dcrt0.cc (wow64_respawn): New static variable.
(wow64_started_from_native64): New function to check if a WOW64 process got started from a native 64 bit process. (respawn_wow64_process): New function to respawn process. (dll_crt0_0): When started from a native parent, check if parent is a 64 bit process. If so, return early. (_dll_crt0): Respawn WOW64 process here if required. * init.cc (respawn_wow64_process): Remove. (dll_entry): Rename wow64_test_stack_marker to test_stack_marker. Drop WOW64 test here.
This commit is contained in:
		| @@ -1,3 +1,17 @@ | ||||
| 2011-12-12  Corinna Vinschen  <vinschen@redhat.com> | ||||
| 	    Christopher Faylor  <me.cygwin2011@cgf.cx> | ||||
|  | ||||
| 	* dcrt0.cc (wow64_respawn): New static variable. | ||||
| 	(wow64_started_from_native64): New function to check if a WOW64 | ||||
| 	process got started from a native 64 bit process. | ||||
| 	(respawn_wow64_process): New function to respawn process. | ||||
| 	(dll_crt0_0): When started from a native parent, check if parent | ||||
| 	is a 64 bit process.  If so, return early. | ||||
| 	(_dll_crt0): Respawn WOW64 process here if required. | ||||
| 	* init.cc (respawn_wow64_process): Remove. | ||||
| 	(dll_entry): Rename wow64_test_stack_marker to test_stack_marker. | ||||
| 	Drop WOW64 test here. | ||||
|  | ||||
| 2011-12-11  Christopher Faylor  <me.cygwin2011@cgf.cx> | ||||
|  | ||||
| 	* pipe.cc (fhandler_pipe::create): Use debug_printf to print debugging | ||||
|   | ||||
| @@ -646,6 +646,75 @@ init_windows_system_directory () | ||||
|   windows_system_directory[windows_system_directory_length] = L'\0'; | ||||
| } | ||||
|  | ||||
| static bool NO_COPY wow64_respawn = false; | ||||
|  | ||||
| inline static bool | ||||
| wow64_started_from_native64 () | ||||
| { | ||||
|   /* On Windows XP 64 and 2003 64 there's a problem with processes running | ||||
|      under WOW64.  The first process started from a 64 bit process has an | ||||
|      unusual stack address for the main thread.  That is, an address which | ||||
|      is in the usual space occupied by the process image, but below the auto | ||||
|      load address of DLLs.  If we encounter this situation, check if we | ||||
|      really have been started from a 64 bit process here.  If so, we exit | ||||
|      early from dll_crt0_0 and respawn first thing in dll_crt0_1.  This | ||||
|      ping-pong game is necessary to workaround a problem observed on | ||||
|      Windows 2003 R2 64.  Starting with Cygwin 1.7.10 we don't link against | ||||
|      advapi32.dll anymore.  However, *any* process linked against advapi32, | ||||
|      directly or indirectly, now fails to respawn if respawn_wow_64_process | ||||
|      is called during DLL_PROCESS_ATTACH initialization.  In that case | ||||
|      CreateProcessW returns with ERROR_ACCESS_DENIED for some reason. | ||||
|      Calling CreateProcessW later, inside dll_crt0_1 and so outside of | ||||
|      dll initialization works as before, though. */ | ||||
|   NTSTATUS ret; | ||||
|   PROCESS_BASIC_INFORMATION pbi; | ||||
|   HANDLE parent; | ||||
|  | ||||
|   ULONG wow64 = TRUE;   /* Opt on the safe side. */ | ||||
|  | ||||
|   /* Unfortunately there's no simpler way to retrieve the | ||||
|      parent process in NT, as far as I know.  Hints welcome. */ | ||||
|   ret = NtQueryInformationProcess (NtCurrentProcess (), | ||||
|                                    ProcessBasicInformation, | ||||
|                                    &pbi, sizeof pbi, NULL); | ||||
|   if (NT_SUCCESS (ret) | ||||
|       && (parent = OpenProcess (PROCESS_QUERY_INFORMATION, | ||||
|                                 FALSE, | ||||
|                                 pbi.InheritedFromUniqueProcessId))) | ||||
|     { | ||||
|       NtQueryInformationProcess (parent, ProcessWow64Information, | ||||
|                                  &wow64, sizeof wow64, NULL); | ||||
|       CloseHandle (parent); | ||||
|     } | ||||
|   return !wow64; | ||||
| } | ||||
|  | ||||
| inline static void | ||||
| respawn_wow64_process () | ||||
| { | ||||
|   /* The parent is a real 64 bit process.  Respawn. */ | ||||
|   WCHAR path[PATH_MAX]; | ||||
|   PROCESS_INFORMATION pi; | ||||
|   STARTUPINFOW si; | ||||
|   DWORD ret = 0; | ||||
|  | ||||
|   GetModuleFileNameW (NULL, path, PATH_MAX); | ||||
|   GetStartupInfoW (&si); | ||||
|   if (!CreateProcessW (path, GetCommandLineW (), NULL, NULL, TRUE, | ||||
| 		       CREATE_DEFAULT_ERROR_MODE | ||||
| 		       | GetPriorityClass (GetCurrentProcess ()), | ||||
| 		       NULL, NULL, &si, &pi)) | ||||
|     api_fatal ("Failed to create process <%W> <%W>, %E", | ||||
| 	       path, GetCommandLineW ()); | ||||
|   CloseHandle (pi.hThread); | ||||
|   if (WaitForSingleObject (pi.hProcess, INFINITE) == WAIT_FAILED) | ||||
|     api_fatal ("Waiting for process %d failed, %E", pi.dwProcessId); | ||||
|   GetExitCodeProcess (pi.hProcess, &ret); | ||||
|   CloseHandle (pi.hProcess); | ||||
|   TerminateProcess (GetCurrentProcess (), ret); | ||||
|   ExitProcess (ret); | ||||
| } | ||||
|  | ||||
| void | ||||
| dll_crt0_0 () | ||||
| { | ||||
| @@ -677,7 +746,18 @@ dll_crt0_0 () | ||||
|   cygthread::init (); | ||||
|  | ||||
|   if (!child_proc_info) | ||||
|     { | ||||
|       memory_init (true); | ||||
|       /* WOW64 bit process with stack at unusual address?  Check if we | ||||
| 	 have been started from 64 bit process ans set wow64_respawn. | ||||
| 	 Full description in wow64_started_from_native64 above. */ | ||||
|       BOOL wow64_test_stack_marker; | ||||
|       if (wincap.is_wow64 () | ||||
| 	  && &wow64_test_stack_marker >= (PBOOL) 0x400000 | ||||
| 	  && &wow64_test_stack_marker <= (PBOOL) 0x10000000 | ||||
| 	  && (wow64_respawn = wow64_started_from_native64 ())) | ||||
| 	return; | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       cygwin_user_h = child_proc_info->user_h; | ||||
| @@ -912,6 +992,10 @@ __cygwin_exit_return:			\n\ | ||||
| extern "C" void __stdcall | ||||
| _dll_crt0 () | ||||
| { | ||||
|   /* Respawn WOW64 process started from native 64 bit process.  See comment | ||||
|      in wow64_started_from_native64 above for a full description. */ | ||||
|   if (wow64_respawn) | ||||
|     respawn_wow64_process (); | ||||
| #ifdef __i386__ | ||||
|   _feinitialise (); | ||||
| #endif | ||||
|   | ||||
| @@ -64,58 +64,12 @@ munge_threadfunc () | ||||
|     } | ||||
| } | ||||
|  | ||||
| inline static void | ||||
| respawn_wow64_process () | ||||
| { | ||||
|   NTSTATUS ret; | ||||
|   PROCESS_BASIC_INFORMATION pbi; | ||||
|   HANDLE parent; | ||||
|  | ||||
|   ULONG wow64 = TRUE;	/* Opt on the safe side. */ | ||||
|  | ||||
|   /* Unfortunately there's no simpler way to retrieve the | ||||
|      parent process in NT, as far as I know.  Hints welcome. */ | ||||
|   ret = NtQueryInformationProcess (NtCurrentProcess (), | ||||
| 				   ProcessBasicInformation, | ||||
| 				   &pbi, sizeof pbi, NULL); | ||||
|   if (NT_SUCCESS (ret) | ||||
|       && (parent = OpenProcess (PROCESS_QUERY_INFORMATION, | ||||
| 				FALSE, | ||||
| 				pbi.InheritedFromUniqueProcessId))) | ||||
|     { | ||||
|       NtQueryInformationProcess (parent, ProcessWow64Information, | ||||
| 				 &wow64, sizeof wow64, NULL); | ||||
|       CloseHandle (parent); | ||||
|     } | ||||
|  | ||||
|   /* The parent is a real 64 bit process?  Respawn! */ | ||||
|   if (!wow64) | ||||
|     { | ||||
|       PROCESS_INFORMATION pi; | ||||
|       STARTUPINFOW si; | ||||
|       DWORD ret = 0; | ||||
|  | ||||
|       GetStartupInfoW (&si); | ||||
|       if (!CreateProcessW (NULL, GetCommandLineW (), NULL, NULL, TRUE, | ||||
| 			   CREATE_DEFAULT_ERROR_MODE | ||||
| 			   | GetPriorityClass (GetCurrentProcess ()), | ||||
| 			   NULL, NULL, &si, &pi)) | ||||
| 	api_fatal ("Failed to create process <%s>, %E", GetCommandLineA ()); | ||||
|       CloseHandle (pi.hThread); | ||||
|       if (WaitForSingleObject (pi.hProcess, INFINITE) == WAIT_FAILED) | ||||
| 	api_fatal ("Waiting for process %d failed, %E", pi.dwProcessId); | ||||
|       GetExitCodeProcess (pi.hProcess, &ret); | ||||
|       CloseHandle (pi.hProcess); | ||||
|       ExitProcess (ret); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void dll_crt0_0 (); | ||||
|  | ||||
| extern "C" BOOL WINAPI | ||||
| dll_entry (HANDLE h, DWORD reason, void *static_load) | ||||
| { | ||||
|   BOOL wow64_test_stack_marker; | ||||
|   BOOL test_stack_marker; | ||||
|  | ||||
|   switch (reason) | ||||
|     { | ||||
| @@ -126,16 +80,6 @@ dll_entry (HANDLE h, DWORD reason, void *static_load) | ||||
|       cygwin_hmodule = (HMODULE) h; | ||||
|       dynamically_loaded = (static_load == NULL); | ||||
|  | ||||
|       /* Is the stack at an unusual address?  That is, an address which | ||||
| 	 is in the usual space occupied by the process image, but below | ||||
| 	 the auto load address of DLLs? | ||||
| 	 Check if we're running in WOW64 on a 64 bit machine *and* are | ||||
| 	 spawned by a genuine 64 bit process.  If so, respawn. */ | ||||
|       if (wincap.is_wow64 () | ||||
| 	  && &wow64_test_stack_marker >= (PBOOL) 0x400000 | ||||
| 	  && &wow64_test_stack_marker <= (PBOOL) 0x10000000) | ||||
| 	respawn_wow64_process (); | ||||
|  | ||||
|       dll_crt0_0 (); | ||||
|       _my_oldfunc = TlsAlloc (); | ||||
|       dll_finished_loading = true; | ||||
| @@ -150,7 +94,7 @@ dll_entry (HANDLE h, DWORD reason, void *static_load) | ||||
|       break; | ||||
|     case DLL_THREAD_DETACH: | ||||
|       if (dll_finished_loading | ||||
| 	  && (PVOID) &_my_tls > (PVOID) &wow64_test_stack_marker | ||||
| 	  && (PVOID) &_my_tls > (PVOID) &test_stack_marker | ||||
| 	  && _my_tls.isinitialized ()) | ||||
| 	_my_tls.remove (0); | ||||
|       /* Windows 2000 has a bug in NtTerminateThread.  Instead of releasing | ||||
|   | ||||
		Reference in New Issue
	
	Block a user