]> sourceware.org Git - newlib-cygwin.git/commitdiff
On 64 bit, only create new thread stack if started from 32 bit process on affected...
authorCorinna Vinschen <corinna@vinschen.de>
Thu, 3 Dec 2015 21:56:44 +0000 (22:56 +0100)
committerCorinna Vinschen <corinna@vinschen.de>
Thu, 3 Dec 2015 21:56:44 +0000 (22:56 +0100)
        * dcrt0.cc (dll_crt0_0): On 64 bit, set wow64_needs_stack_adjustment
        if not started from a 64 bit process.
        (_dll_crt0): Enable wow64_needs_stack_adjustment branch on 64 bit
        as well.  Remove 64 bit only code.  Introduce CREATE_STACK and
        FIX_STACK macros to conditionalize the code.  Rearrange and
        partially rewrite comments.
        * wincap.h (wincaps::has_3264_stack_broken): New element.
        * wincap.cc: Implement above element throughout.
        (wincapc::init): Set has_3264_stack_broken to false on 32 bit.
        * wow64.cc: Enable functionality on 64 bit architecture, except for
        wow64_revert_to_original_stack.  Enhance comments to explain.
        (wow64_eval_expected_main_stack): Make 64 bit clean.
        (wow64_test_for_64bit_parent): Ditto.
        * wow64.h: Export wow64_revert_to_original_stack on 32 bit only,
        everything else on all architectures.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
winsup/cygwin/ChangeLog
winsup/cygwin/dcrt0.cc
winsup/cygwin/wincap.cc
winsup/cygwin/wincap.h
winsup/cygwin/wow64.cc
winsup/cygwin/wow64.h

index 59e8cce609345e71e72c0947fd7007a445235525..747e8765e39ac6b970bf0d62d70670342711d4af 100644 (file)
@@ -1,3 +1,21 @@
+2015-12-03  Corinna Vinschen  <corinna@vinschen.de>
+
+       * dcrt0.cc (dll_crt0_0): On 64 bit, set wow64_needs_stack_adjustment
+       if not started from a 64 bit process.
+       (_dll_crt0): Enable wow64_needs_stack_adjustment branch on 64 bit
+       as well.  Remove 64 bit only code.  Introduce CREATE_STACK and
+       FIX_STACK macros to conditionalize the code.  Rearrange and
+       partially rewrite comments.
+       * wincap.h (wincaps::has_3264_stack_broken): New element.
+       * wincap.cc: Implement above element throughout.
+       (wincapc::init): Set has_3264_stack_broken to false on 32 bit.
+       * wow64.cc: Enable functionality on 64 bit architecture, except for
+       wow64_revert_to_original_stack.  Enhance comments to explain.
+       (wow64_eval_expected_main_stack): Make 64 bit clean.
+       (wow64_test_for_64bit_parent): Ditto.
+       * wow64.h: Export wow64_revert_to_original_stack on 32 bit only,
+       everything else on all architectures.
+
 2015-12-03  Corinna Vinschen  <corinna@vinschen.de>
 
        * fhandler_process.cc (thread_info::thread_info): Accommodate the fact
index 5865426e1ddbb5c00a1c5ca5acc52c5fe652607b..26b7ec3b423703d9e709b39992bc81352cb6782c 100644 (file)
@@ -782,6 +782,11 @@ dll_crt0_0 ()
         description in wow64_test_for_64bit_parent. */
       if (wincap.wow64_has_secondary_stack ())
        wow64_needs_stack_adjustment = wow64_test_for_64bit_parent ();
+#else
+      /* Windows 10 1511 has a stack move when a 64 bit process is started from
+        a 32 bit process, just as it was vice versa in XP/2003. */
+      if (wincap.has_3264_stack_broken ())
+       wow64_needs_stack_adjustment = !wow64_test_for_64bit_parent ();
 #endif /* !__x86_64__ */
     }
   else
@@ -1062,67 +1067,50 @@ __cygwin_exit_return:                   \n\
 extern "C" void __stdcall
 _dll_crt0 ()
 {
-#ifndef __x86_64__
+#ifdef __x86_64__
+  /* Handle 64 bit process on Windows 10 rel 1511 which has been started from
+     32 bit WOW64 process.  See comment in wow64_test_for_64bit_parent for a
+     problem description.  Unfortunately the areas the stacks would have to
+     be moved to are both taken by "something else"(tm) in both, forker and
+     forkee, so we can't use the wow64_revert_to_original_stack method as in
+     the 32 bit case.  Rather, we move the main thread stack to the stack area
+     reserved for pthread stacks for this process. */
+#define CREATE_STACK(a)        create_new_main_thread_stack(a)
+#define FIX_STACK(s)   __asm__ ("\n"                           \
+                                "movq %[ADDR], %%rsp \n"       \
+                                "movq  %%rsp, %%rbp  \n"       \
+                                : : [ADDR] "r" (s))
+#else
   /* Handle WOW64 process on XP/2K3 which has been started from native 64 bit
      process.  See comment in wow64_test_for_64bit_parent for a full problem
      description. */
+#define CREATE_STACK(a)        wow64_revert_to_original_stack(a)
+#define FIX_STACK(s)   __asm__ ("\n"                           \
+                                "movl  %[ADDR], %%esp \n"      \
+                                "xorl  %%ebp, %%ebp   \n"      \
+                                : : [ADDR] "r" (s))
+#endif
   if (wow64_needs_stack_adjustment && !dynamically_loaded)
     {
       /* Must be static since it's referenced after the stack and frame
         pointer registers have been changed. */
-      static PVOID allocationbase = 0;
+      static PVOID allocationbase;
 
-      /* Check if we just move the stack.  If so, wow64_revert_to_original_stack
-        returns a non-NULL, 16 byte aligned address.  See comments in
-        wow64_revert_to_original_stack for the gory details. */
-      PVOID stackaddr = wow64_revert_to_original_stack (allocationbase);
+      PVOID stackaddr = CREATE_STACK (allocationbase);
       if (stackaddr)
        {
          /* 2nd half of the stack move.  Set stack pointer to new address.
             Set frame pointer to 0. */
-         __asm__ ("\n\
-                  movl  %[ADDR], %%esp \n\
-                  xorl  %%ebp, %%ebp   \n"
-                  : : [ADDR] "r" (stackaddr));
+         FIX_STACK (stackaddr);
          /* Now we're back on the original stack.  Free up space taken by the
             former main thread stack and set DeallocationStack correctly. */
          VirtualFree (NtCurrentTeb ()->DeallocationStack, 0, MEM_RELEASE);
          NtCurrentTeb ()->DeallocationStack = allocationbase;
        }
       else
-       /* Fall back to respawn if wow64_revert_to_original_stack fails. */
+       /* Fall back to respawning if creating a new stack fails. */
        wow64_respawn_process ();
     }
-#else
-  /* Starting with Windows 10 rel 1511, the main stack of an application is
-     not reproducible if a 64 bit process has been started from a 32 bit
-     process.  Given that we have enough virtual address space on 64 bit
-     anyway, we now move the main thread stack to the stack area reserved for
-     pthread stacks.  This allows a reproducible stack space under our own
-     control and avoids collision with the OS. */
-  if (!in_forkee && !dynamically_loaded)
-    {
-      /* Must be static since it's referenced after the stack and frame
-        pointer registers have been changed. */
-      static PVOID allocationbase;
-
-      PVOID stackaddr = create_new_main_thread_stack (allocationbase);
-      if (stackaddr)
-       {
-         /* 2nd half of the stack move.  Set stack pointer to new address.
-            Don't set frame pointer to 0 since x86_64 uses the stack while
-            evaluating NtCurrentTeb (). */
-         __asm__ ("\n\
-                  movq %[ADDR], %%rsp \n\
-                  movq  %%rsp, %%rbp   \n"
-                  : : [ADDR] "r" (stackaddr));
-         /* Now we're back on the new stack.  Free up space taken by the
-            former main thread stack and set DeallocationStack correctly. */
-         VirtualFree (NtCurrentTeb ()->DeallocationStack, 0, MEM_RELEASE);
-         NtCurrentTeb ()->DeallocationStack = allocationbase;
-       }
-    }
-#endif /* !__x86_64__ */
   _feinitialise ();
 #ifndef __x86_64__
   main_environ = user_data->envptr;
index 4bf62d7259a56c375a1f0a5b71745caa14a5de4e..6da4b0b5acf05d1c499abe6a45ab8ed33dfa2e8a 100644 (file)
@@ -52,6 +52,7 @@ wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = {
   has_processor_groups:false,
   has_broken_prefetchvm:false,
   has_new_pebteb_region:false,
+  has_3264_stack_broken:false,
 };
 
 wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -86,6 +87,7 @@ wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
   has_processor_groups:false,
   has_broken_prefetchvm:false,
   has_new_pebteb_region:false,
+  has_3264_stack_broken:false,
 };
 
 wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -120,6 +122,7 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
   has_processor_groups:false,
   has_broken_prefetchvm:false,
   has_new_pebteb_region:false,
+  has_3264_stack_broken:false,
 };
 
 wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -154,6 +157,7 @@ wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
   has_processor_groups:true,
   has_broken_prefetchvm:false,
   has_new_pebteb_region:false,
+  has_3264_stack_broken:false,
 };
 
 wincaps wincap_8 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -188,6 +192,7 @@ wincaps wincap_8 __attribute__((section (".cygwin_dll_common"), shared)) = {
   has_processor_groups:true,
   has_broken_prefetchvm:false,
   has_new_pebteb_region:false,
+  has_3264_stack_broken:false,
 };
 
 wincaps wincap_10 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -222,6 +227,7 @@ wincaps wincap_10 __attribute__((section (".cygwin_dll_common"), shared)) = {
   has_processor_groups:true,
   has_broken_prefetchvm:true,
   has_new_pebteb_region:false,
+  has_3264_stack_broken:false,
 };
 
 wincaps wincap_10_1511 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -256,6 +262,7 @@ wincaps wincap_10_1511 __attribute__((section (".cygwin_dll_common"), shared)) =
   has_processor_groups:true,
   has_broken_prefetchvm:false,
   has_new_pebteb_region:true,
+  has_3264_stack_broken:true,
 };
 
 wincapc wincap __attribute__((section (".cygwin_dll_common"), shared));
@@ -320,6 +327,10 @@ wincapc::init ()
      target process on 64 bit XP/2003 in native 64 bit mode only.  Reset the
      flag here for 32 bit. */
   ((wincaps *)caps)->has_broken_rtl_query_process_debug_information = false;
+  /* Windows 10 1511 has a stack move when a 64 bit process is started from
+     a 32 bit process, just as it was vice versa in XP/2003.  Reset the flag
+     here for 32 bit. */
+  ((wincaps *)caps)->has_3264_stack_broken = false;
   if (NT_SUCCESS (NtQueryInformationProcess (NtCurrentProcess (),
                                             ProcessWow64Information,
                                             &wow64, sizeof wow64, NULL))
index 4508974f50b02a0f522cee80ed8e9fdbdc526d1e..05a73f9252359c253d67b23ce6059b53021eb3de 100644 (file)
@@ -45,6 +45,7 @@ struct wincaps
   unsigned has_processor_groups                                : 1;
   unsigned has_broken_prefetchvm                       : 1;
   unsigned has_new_pebteb_region                       : 1;
+  unsigned has_3264_stack_broken                       : 1;
 };
 
 class wincapc
@@ -104,6 +105,7 @@ public:
   bool IMPLEMENT (has_processor_groups)
   bool IMPLEMENT (has_broken_prefetchvm)
   bool IMPLEMENT (has_new_pebteb_region)
+  bool IMPLEMENT (has_3264_stack_broken)
 
 #undef IMPLEMENT
 };
index 240baa8986c6d12c2949ed415c68a0b609d4c802..f91a6d8557bf248c887fbb9465971bcac1051161 100644 (file)
@@ -8,10 +8,6 @@ This software is a copyrighted work licensed under the terms of the
 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
-#ifndef __x86_64__
-/* WOW64 only plays a role in the 32 bit version.  Don't use any of this
-   in the 64 bit version. */
-
 #include "winsup.h"
 #include "cygtls.h"
 #include "ntdll.h"
@@ -25,11 +21,11 @@ static void
 wow64_eval_expected_main_stack (PVOID &allocbase, PVOID &stackbase)
 {
   PIMAGE_DOS_HEADER dosheader;
-  PIMAGE_NT_HEADERS32 ntheader;
-  DWORD size;
+  PIMAGE_NT_HEADERS ntheader;
+  SIZE_T size;
 
   dosheader = (PIMAGE_DOS_HEADER) GetModuleHandle (NULL);
-  ntheader = (PIMAGE_NT_HEADERS32) ((PBYTE) dosheader + dosheader->e_lfanew);
+  ntheader = (PIMAGE_NT_HEADERS) ((PBYTE) dosheader + dosheader->e_lfanew);
   /* The main thread stack is expected to be located at 0x30000, which is the
      case for all observed NT systems up to Server 2003 R2, unless the
      stacksize requested by the StackReserve field in the PE/COFF header is
@@ -41,8 +37,15 @@ wow64_eval_expected_main_stack (PVOID &allocbase, PVOID &stackbase)
      stack address on Vista/2008 64 bit is 0x80000 and on W7/2K8R2 64 bit
      it is 0x90000.  However, this is no problem because the system sticks
      to that address for all WOW64 processes, not only for the first one
-     started from a 64 bit parent. */
+     started from a 64 bit parent.
+
+     On 64 bit W10 1511 the stack starts at 0x400000 by default.  See comment
+     in wow64_test_for_64bit_parent. */
+#ifdef __x86_64__
+  allocbase = (PVOID) 0x400000;
+#else
   allocbase = (PVOID) 0x30000;
+#endif
   /* Stack size.  The OS always rounds the size up to allocation granularity
      and it never allocates less than 256K. */
   size = roundup2 (ntheader->OptionalHeader.SizeOfStackReserve,
@@ -71,11 +74,19 @@ wow64_test_for_64bit_parent ()
      we have to "alloc_stack_hard_way".  However, this fails in almost all
      cases because the stack slot of the parent process is taken by something
      else in the child process.
-     What we do here is to check if the current stack is the excpected main
+     What we do here is to check if the current stack is the expected main
      thread stack and if not, if we really have been started from a 64 bit
      process here.  If so, we note this fact in wow64_needs_stack_adjustment
      so we can workaround the stack problem in _dll_crt0.  See there for how
      we go along. */
+
+  /* Amazing but true: Starting with Windows 10 1511 this problem has been
+     reintroduced, just in the opposite direction: If a 64 bit process is
+     created from a 32 bit WOW64 process, the main thread stack in the 64
+     bit child gets moved to another location than the default.  In the
+     forked child, the stack is back where it usually is when started from
+     another 64 bit process.  Therefore we have to be able to recognize
+     this scenarion now on 64 bit as well.  We I don't believe it... */
   NTSTATUS ret;
   PROCESS_BASIC_INFORMATION pbi;
   HANDLE parent;
@@ -86,7 +97,7 @@ wow64_test_for_64bit_parent ()
   /* First check if the current stack is where it belongs.  If so, we don't
      have to do anything special.  This is the case on Vista and later. */
   wow64_eval_expected_main_stack (allocbase, stackbase);
-  if (&wow64 >= (PULONG) allocbase && &wow64 < (PULONG) stackbase)
+  if (&wow64 >= (PULONG_PTR) allocbase && &wow64 < (PULONG_PTR) stackbase)
     return false;
 
   /* Check if the parent is a native 64 bit process.  Unfortunately there's
@@ -107,6 +118,8 @@ wow64_test_for_64bit_parent ()
   return !wow64;
 }
 
+#ifndef __x86_64__
+
 PVOID
 wow64_revert_to_original_stack (PVOID &allocationbase)
 {
@@ -177,6 +190,8 @@ wow64_revert_to_original_stack (PVOID &allocationbase)
   return PTR_ADD (NtCurrentTeb()->Tib.StackBase, -16);
 }
 
+#endif /* !__x86_64__ */
+
 /* Respawn WOW64 process. This is only called if we can't reuse the original
    stack.  See comment in wow64_revert_to_original_stack for details.  See
    _dll_crt0 for the call of this function.
@@ -211,5 +226,3 @@ wow64_respawn_process ()
   TerminateProcess (GetCurrentProcess (), ret);
   ExitProcess (ret);
 }
-
-#endif /* !__x86_64__ */
index a0b5b318d948bec2d9446ddcc84c3a3df17f8600..150561c8c2608f3767194d2396f4406d71a2ce79 100644 (file)
@@ -1,6 +1,6 @@
 /* wow64.h
 
-   Copyright 2011, 2012 Red Hat, Inc.
+   Copyright 2011, 2012, 2015 Red Hat, Inc.
 
 This file is part of Cygwin.
 
@@ -8,14 +8,12 @@ This software is a copyrighted work licensed under the terms of the
 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
-#ifndef __x86_64__
-/* WOW64 only plays a role in the 32 bit version.  Don't use any of this
-   in the 64 bit version. */
-
 extern bool NO_COPY wow64_needs_stack_adjustment;
-
 extern bool wow64_test_for_64bit_parent ();
-extern PVOID wow64_revert_to_original_stack (PVOID &allocationbase);
 extern void wow64_respawn_process () __attribute__ ((noreturn));
 
+#ifndef __x86_64__
+
+extern PVOID wow64_revert_to_original_stack (PVOID &allocationbase);
+
 #endif /* !__x86_64__ */
This page took 0.043229 seconds and 5 git commands to generate.