This is the mail archive of the cygwin-cvs@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[newlib-cygwin] On 64 bit, only create new thread stack if started from 32 bit process on affected platforms


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=12743c2d5d2721f3a80b4d7671a349be03c1f520

commit 12743c2d5d2721f3a80b4d7671a349be03c1f520
Author: Corinna Vinschen <corinna@vinschen.de>
Date:   Thu Dec 3 22:56:44 2015 +0100

    On 64 bit, only create new thread stack if started from 32 bit process on affected platforms
    
            * 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>

Diff:
---
 winsup/cygwin/ChangeLog | 18 +++++++++++++
 winsup/cygwin/dcrt0.cc  | 70 ++++++++++++++++++++-----------------------------
 winsup/cygwin/wincap.cc | 11 ++++++++
 winsup/cygwin/wincap.h  |  2 ++
 winsup/cygwin/wow64.cc  | 37 +++++++++++++++++---------
 winsup/cygwin/wow64.h   | 12 ++++-----
 6 files changed, 90 insertions(+), 60 deletions(-)

diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 59e8cce..747e876 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,5 +1,23 @@
 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
 	that TEBs take two pages.
 	(thread_info::fill_if_match): Rewrite the method for post W10 1511 TEB
diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
index 5865426..26b7ec3 100644
--- a/winsup/cygwin/dcrt0.cc
+++ b/winsup/cygwin/dcrt0.cc
@@ -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;
diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc
index 4bf62d7..6da4b0b 100644
--- a/winsup/cygwin/wincap.cc
+++ b/winsup/cygwin/wincap.cc
@@ -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))
diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h
index 4508974..05a73f9 100644
--- a/winsup/cygwin/wincap.h
+++ b/winsup/cygwin/wincap.h
@@ -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
 };
diff --git a/winsup/cygwin/wow64.cc b/winsup/cygwin/wow64.cc
index 240baa8..f91a6d8 100644
--- a/winsup/cygwin/wow64.cc
+++ b/winsup/cygwin/wow64.cc
@@ -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__ */
diff --git a/winsup/cygwin/wow64.h b/winsup/cygwin/wow64.h
index a0b5b31..150561c 100644
--- a/winsup/cygwin/wow64.h
+++ b/winsup/cygwin/wow64.h
@@ -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__ */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]