OSDN Git Service

* dcrt0.cc (get_cygwin_startup_info): Change zeros to DWORD array.
authorcorinna <corinna>
Tue, 5 Dec 2006 10:59:20 +0000 (10:59 +0000)
committercorinna <corinna>
Tue, 5 Dec 2006 10:59:20 +0000 (10:59 +0000)
Expect first DWORD in child_info struct being set to non-zero if
wincap.needs_count_in_si_lpres2 is set.  Add comment to explain why.
* fork.cc (frok::parent): Set ch.zero[0] to a sensible count value
if wincap.needs_count_in_si_lpres2 is set.
* spawn.cc (spawn_guts): Ditto.  Add filler bytes after ch on stack
to accomodate needs_count_in_si_lpres2.
* wincap.h: Define needs_count_in_si_lpres2 throughout.
* wincap.cc: Ditto.

winsup/cygwin/ChangeLog
winsup/cygwin/dcrt0.cc
winsup/cygwin/fork.cc
winsup/cygwin/spawn.cc
winsup/cygwin/wincap.cc
winsup/cygwin/wincap.h

index 8e77814..8da34ac 100644 (file)
@@ -1,3 +1,15 @@
+2006-12-04  Corinna Vinschen  <corinna@vinschen.de>
+
+       * dcrt0.cc (get_cygwin_startup_info): Change zeros to DWORD array.
+       Expect first DWORD in child_info struct being set to non-zero if
+       wincap.needs_count_in_si_lpres2 is set.  Add comment to explain why.
+       * fork.cc (frok::parent): Set ch.zero[0] to a sensible count value
+       if wincap.needs_count_in_si_lpres2 is set.
+       * spawn.cc (spawn_guts): Ditto.  Add filler bytes after ch on stack
+       to accomodate needs_count_in_si_lpres2.
+       * wincap.h: Define needs_count_in_si_lpres2 throughout.
+       * wincap.cc: Ditto.
+
 2006-11-29  Corinna Vinschen  <corinna@vinschen.de>
 
        * dir.cc (mkdir): Check last path component for "..".
index 2a7b672..023f768 100644 (file)
@@ -590,10 +590,36 @@ child_info *
 get_cygwin_startup_info ()
 {
   STARTUPINFO si;
-  char zeros[sizeof (child_proc_info->zero)] = {0};
+  DWORD zeros[sizeof (child_proc_info->zero)
+             / sizeof (child_proc_info->zero[0])] = {0};
 
   GetStartupInfo (&si);
   child_info *res = (child_info *) si.lpReserved2;
+
+  /* It appears that when running under WOW64 on Vista 64, the first DWORD
+     value in the datastructure lpReserved2 is pointing to (zero[0] in
+     Cygwin), has to reflect the size of that datastructure as used in the
+     Microsoft C runtime (a count value, counting the number of elements in
+     two subsequent arrays, BYTE[count and HANDLE[count]), even though the C
+     runtime isn't used.  Otherwise, if zero[0] is 0 or too small, the
+     datastructure gets overwritten.
+
+     This seems to be a bug in Vista's WOW64, which apparently copies the
+     lpReserved2 datastructure not using the cbReserved2 size information,
+     but using the information given in the first DWORD within lpReserved2
+     instead.  Funny enough, 32 bit Vista doesn't care if zero[0] is 0 or a
+     non-0 count value, while older versions of Windows might crash if
+     zero[0] is set to a non-zero value, as observed at least on XP 64.
+
+     exec/spawn as well as fork write an appropriate value into zero[0] now,
+     depending on the wincap.needs_count_in_si_lpres2 flag.  The value is
+     sizeof (child_info_*) / 5 which results in a count which covers the
+     full datastructure, plus not more than 4 extra bytes.  This is ok as
+     long as the child_info structure is cosily stored within a bigger
+     datastructure. */
+  if (wincap.needs_count_in_si_lpres2 ())
+    zeros[0] = si.cbReserved2 / 5;
+
   if (si.cbReserved2 < EXEC_MAGIC_SIZE || !res
       || memcmp (res->zero, zeros, sizeof (res->zero)) != 0)
     res = NULL;
index ed85e74..cc5bece 100644 (file)
@@ -280,9 +280,14 @@ frok::parent (void *stack_here)
 
   memset (&si, 0, sizeof (si));
   si.cb = sizeof (STARTUPINFO);
+
   si.lpReserved2 = (LPBYTE) &ch;
   si.cbReserved2 = sizeof (ch);
 
+  /* See comment in dcrt0.cc, function get_cygwin_startup_info. */
+  if (wincap.needs_count_in_si_lpres2 ())
+    ch.zero[0] = sizeof (ch) / 5;
+
   syscall_printf ("CreateProcess (%s, %s, 0, 0, 1, %p, 0, 0, %p, %p)",
                  myself->progname, myself->progname, c_flags, &si, &pi);
   bool locked = __malloc_lock ();
index d1750f7..12418df 100644 (file)
@@ -298,7 +298,13 @@ spawn_guts (const char * prog_arg, const char *const *argv,
   pthread_cleanup_push (do_cleanup, (void *) &cleanup);
   av newargv;
   linebuf one_line;
-  child_info_spawn ch;
+  /* Allocate slightly bigger for call to CreateProcess to accomodate
+     needs_count_in_si_lpres2. */
+  struct {
+    child_info_spawn ch;
+    char filler[4];
+  } _ch;
+#define ch     _ch.ch
 
   char *envblock = NULL;
   path_conv real_path;
@@ -481,6 +487,10 @@ spawn_guts (const char * prog_arg, const char *const *argv,
   si.lpReserved2 = (LPBYTE) &ch;
   si.cbReserved2 = sizeof (ch);
 
+  /* See comment in dcrt0.cc, function get_cygwin_startup_info. */
+  if (wincap.needs_count_in_si_lpres2 ())
+    ch.zero[0] = sizeof (ch) / 5;
+
   /* When ruid != euid we create the new process under the current original
      account and impersonate in child, this way maintaining the different
      effective vs. real ids.
@@ -724,6 +734,7 @@ out:
     free (envblock);
   pthread_cleanup_pop (1);
   return (int) res;
+#undef ch
 }
 
 extern "C" int
index 85405ba..2df0062 100644 (file)
@@ -70,6 +70,7 @@ static NO_COPY wincaps wincap_unknown = {
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
   needs_logon_sid_in_sid_list:false,
+  needs_count_in_si_lpres2:false,
 };
 
 static NO_COPY wincaps wincap_95 = {
@@ -131,6 +132,7 @@ static NO_COPY wincaps wincap_95 = {
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
   needs_logon_sid_in_sid_list:false,
+  needs_count_in_si_lpres2:false,
 };
 
 static NO_COPY wincaps wincap_95osr2 = {
@@ -192,6 +194,7 @@ static NO_COPY wincaps wincap_95osr2 = {
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
   needs_logon_sid_in_sid_list:false,
+  needs_count_in_si_lpres2:false,
 };
 
 static NO_COPY wincaps wincap_98 = {
@@ -253,6 +256,7 @@ static NO_COPY wincaps wincap_98 = {
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
   needs_logon_sid_in_sid_list:false,
+  needs_count_in_si_lpres2:false,
 };
 
 static NO_COPY wincaps wincap_98se = {
@@ -314,6 +318,7 @@ static NO_COPY wincaps wincap_98se = {
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
   needs_logon_sid_in_sid_list:false,
+  needs_count_in_si_lpres2:false,
 };
 
 static NO_COPY wincaps wincap_me = {
@@ -375,6 +380,7 @@ static NO_COPY wincaps wincap_me = {
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
   needs_logon_sid_in_sid_list:false,
+  needs_count_in_si_lpres2:false,
 };
 
 static NO_COPY wincaps wincap_nt3 = {
@@ -436,6 +442,7 @@ static NO_COPY wincaps wincap_nt3 = {
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
   needs_logon_sid_in_sid_list:true,
+  needs_count_in_si_lpres2:false,
 };
 
 static NO_COPY wincaps wincap_nt4 = {
@@ -497,6 +504,7 @@ static NO_COPY wincaps wincap_nt4 = {
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
   needs_logon_sid_in_sid_list:true,
+  needs_count_in_si_lpres2:false,
 };
 
 static NO_COPY wincaps wincap_nt4sp4 = {
@@ -558,6 +566,7 @@ static NO_COPY wincaps wincap_nt4sp4 = {
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
   needs_logon_sid_in_sid_list:true,
+  needs_count_in_si_lpres2:false,
 };
 
 static NO_COPY wincaps wincap_2000 = {
@@ -619,6 +628,7 @@ static NO_COPY wincaps wincap_2000 = {
   has_buggy_restart_scan:true,
   has_mandatory_integrity_control:false,
   needs_logon_sid_in_sid_list:true,
+  needs_count_in_si_lpres2:false,
 };
 
 static NO_COPY wincaps wincap_xp = {
@@ -680,6 +690,7 @@ static NO_COPY wincaps wincap_xp = {
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
   needs_logon_sid_in_sid_list:false,
+  needs_count_in_si_lpres2:false,
 };
 
 static NO_COPY wincaps wincap_2003 = {
@@ -741,6 +752,7 @@ static NO_COPY wincaps wincap_2003 = {
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:false,
   needs_logon_sid_in_sid_list:false,
+  needs_count_in_si_lpres2:false,
 };
 
 static NO_COPY wincaps wincap_vista = {
@@ -802,6 +814,7 @@ static NO_COPY wincaps wincap_vista = {
   has_buggy_restart_scan:false,
   has_mandatory_integrity_control:true,
   needs_logon_sid_in_sid_list:false,
+  needs_count_in_si_lpres2:true,
 };
 
 wincapc wincap __attribute__((section (".cygwin_dll_common"), shared));
index d40d12c..2928f8d 100644 (file)
@@ -71,6 +71,7 @@ struct wincaps
   unsigned has_buggy_restart_scan                      : 1;
   unsigned has_mandatory_integrity_control             : 1;
   unsigned needs_logon_sid_in_sid_list                 : 1;
+  unsigned needs_count_in_si_lpres2                    : 1;
 };
 
 class wincapc
@@ -148,6 +149,7 @@ public:
   bool IMPLEMENT (has_buggy_restart_scan)
   bool IMPLEMENT (has_mandatory_integrity_control)
   bool IMPLEMENT (needs_logon_sid_in_sid_list)
+  bool IMPLEMENT (needs_count_in_si_lpres2)
 
 #undef IMPLEMENT
 };