* 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:
parent
b11797ad17
commit
cdce73f183
|
@ -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>
|
2011-12-11 Christopher Faylor <me.cygwin2011@cgf.cx>
|
||||||
|
|
||||||
* pipe.cc (fhandler_pipe::create): Use debug_printf to print debugging
|
* 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';
|
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
|
void
|
||||||
dll_crt0_0 ()
|
dll_crt0_0 ()
|
||||||
{
|
{
|
||||||
|
@ -677,7 +746,18 @@ dll_crt0_0 ()
|
||||||
cygthread::init ();
|
cygthread::init ();
|
||||||
|
|
||||||
if (!child_proc_info)
|
if (!child_proc_info)
|
||||||
memory_init (true);
|
{
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
cygwin_user_h = child_proc_info->user_h;
|
cygwin_user_h = child_proc_info->user_h;
|
||||||
|
@ -912,6 +992,10 @@ __cygwin_exit_return: \n\
|
||||||
extern "C" void __stdcall
|
extern "C" void __stdcall
|
||||||
_dll_crt0 ()
|
_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__
|
#ifdef __i386__
|
||||||
_feinitialise ();
|
_feinitialise ();
|
||||||
#endif
|
#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 ();
|
void dll_crt0_0 ();
|
||||||
|
|
||||||
extern "C" BOOL WINAPI
|
extern "C" BOOL WINAPI
|
||||||
dll_entry (HANDLE h, DWORD reason, void *static_load)
|
dll_entry (HANDLE h, DWORD reason, void *static_load)
|
||||||
{
|
{
|
||||||
BOOL wow64_test_stack_marker;
|
BOOL test_stack_marker;
|
||||||
|
|
||||||
switch (reason)
|
switch (reason)
|
||||||
{
|
{
|
||||||
|
@ -126,16 +80,6 @@ dll_entry (HANDLE h, DWORD reason, void *static_load)
|
||||||
cygwin_hmodule = (HMODULE) h;
|
cygwin_hmodule = (HMODULE) h;
|
||||||
dynamically_loaded = (static_load == NULL);
|
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 ();
|
dll_crt0_0 ();
|
||||||
_my_oldfunc = TlsAlloc ();
|
_my_oldfunc = TlsAlloc ();
|
||||||
dll_finished_loading = true;
|
dll_finished_loading = true;
|
||||||
|
@ -150,7 +94,7 @@ dll_entry (HANDLE h, DWORD reason, void *static_load)
|
||||||
break;
|
break;
|
||||||
case DLL_THREAD_DETACH:
|
case DLL_THREAD_DETACH:
|
||||||
if (dll_finished_loading
|
if (dll_finished_loading
|
||||||
&& (PVOID) &_my_tls > (PVOID) &wow64_test_stack_marker
|
&& (PVOID) &_my_tls > (PVOID) &test_stack_marker
|
||||||
&& _my_tls.isinitialized ())
|
&& _my_tls.isinitialized ())
|
||||||
_my_tls.remove (0);
|
_my_tls.remove (0);
|
||||||
/* Windows 2000 has a bug in NtTerminateThread. Instead of releasing
|
/* Windows 2000 has a bug in NtTerminateThread. Instead of releasing
|
||||||
|
|
Loading…
Reference in New Issue