diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2006-12-05 11:34:01 +0000 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2006-12-05 11:34:01 +0000 |
commit | 2c36d592bace7c87156c974b119f5338b917f36b (patch) | |
tree | 2ece4959bcf923a89db8da1eb19506543896b2a1 /winsup | |
parent | 20d4425edbaf65daa59428ba5386370cacac307e (diff) | |
download | newlib-2c36d592bace7c87156c974b119f5338b917f36b.zip newlib-2c36d592bace7c87156c974b119f5338b917f36b.tar.gz newlib-2c36d592bace7c87156c974b119f5338b917f36b.tar.bz2 |
* 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.
Diffstat (limited to 'winsup')
-rw-r--r-- | winsup/cygwin/ChangeLog | 12 | ||||
-rw-r--r-- | winsup/cygwin/dcrt0.cc | 28 | ||||
-rw-r--r-- | winsup/cygwin/fork.cc | 5 | ||||
-rw-r--r-- | winsup/cygwin/spawn.cc | 13 | ||||
-rw-r--r-- | winsup/cygwin/wincap.cc | 13 | ||||
-rw-r--r-- | winsup/cygwin/wincap.h | 2 |
6 files changed, 71 insertions, 2 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 8377226..86fe5c4 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,15 @@ +2006-12-05 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-28 Corinna Vinschen <corinna@vinschen.de> * fhandler.cc (fhandler_base::open): Fix previous patch to handle the diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 2a7b672..023f768 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -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; diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index ed85e74..cc5bece 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -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 (); diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index d1ee321..0903048 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -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. @@ -725,6 +735,7 @@ out: free (envblock); pthread_cleanup_pop (1); return (int) res; +#undef ch } extern "C" int diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc index df6765b..3d1e61d 100644 --- a/winsup/cygwin/wincap.cc +++ b/winsup/cygwin/wincap.cc @@ -68,6 +68,7 @@ static NO_COPY wincaps wincap_unknown = { has_fileid_dirinfo:false, has_exclusiveaddruse:false, has_buggy_restart_scan:false, + needs_count_in_si_lpres2:false, }; static NO_COPY wincaps wincap_95 = { @@ -127,6 +128,7 @@ static NO_COPY wincaps wincap_95 = { has_fileid_dirinfo:false, has_exclusiveaddruse:false, has_buggy_restart_scan:false, + needs_count_in_si_lpres2:false, }; static NO_COPY wincaps wincap_95osr2 = { @@ -186,6 +188,7 @@ static NO_COPY wincaps wincap_95osr2 = { has_fileid_dirinfo:false, has_exclusiveaddruse:false, has_buggy_restart_scan:false, + needs_count_in_si_lpres2:false, }; static NO_COPY wincaps wincap_98 = { @@ -245,6 +248,7 @@ static NO_COPY wincaps wincap_98 = { has_fileid_dirinfo:false, has_exclusiveaddruse:false, has_buggy_restart_scan:false, + needs_count_in_si_lpres2:false, }; static NO_COPY wincaps wincap_98se = { @@ -304,6 +308,7 @@ static NO_COPY wincaps wincap_98se = { has_fileid_dirinfo:false, has_exclusiveaddruse:false, has_buggy_restart_scan:false, + needs_count_in_si_lpres2:false, }; static NO_COPY wincaps wincap_me = { @@ -363,6 +368,7 @@ static NO_COPY wincaps wincap_me = { has_fileid_dirinfo:false, has_exclusiveaddruse:false, has_buggy_restart_scan:false, + needs_count_in_si_lpres2:false, }; static NO_COPY wincaps wincap_nt3 = { @@ -422,6 +428,7 @@ static NO_COPY wincaps wincap_nt3 = { has_fileid_dirinfo:false, has_exclusiveaddruse:false, has_buggy_restart_scan:false, + needs_count_in_si_lpres2:false, }; static NO_COPY wincaps wincap_nt4 = { @@ -481,6 +488,7 @@ static NO_COPY wincaps wincap_nt4 = { has_fileid_dirinfo:false, has_exclusiveaddruse:false, has_buggy_restart_scan:false, + needs_count_in_si_lpres2:false, }; static NO_COPY wincaps wincap_nt4sp4 = { @@ -540,6 +548,7 @@ static NO_COPY wincaps wincap_nt4sp4 = { has_fileid_dirinfo:false, has_exclusiveaddruse:true, has_buggy_restart_scan:false, + needs_count_in_si_lpres2:false, }; static NO_COPY wincaps wincap_2000 = { @@ -599,6 +608,7 @@ static NO_COPY wincaps wincap_2000 = { has_fileid_dirinfo:true, has_exclusiveaddruse:true, has_buggy_restart_scan:true, + needs_count_in_si_lpres2:false, }; static NO_COPY wincaps wincap_xp = { @@ -658,6 +668,7 @@ static NO_COPY wincaps wincap_xp = { has_fileid_dirinfo:true, has_exclusiveaddruse:true, has_buggy_restart_scan:false, + needs_count_in_si_lpres2:false, }; static NO_COPY wincaps wincap_2003 = { @@ -717,6 +728,7 @@ static NO_COPY wincaps wincap_2003 = { has_fileid_dirinfo:true, has_exclusiveaddruse:true, has_buggy_restart_scan:false, + needs_count_in_si_lpres2:false, }; static NO_COPY wincaps wincap_vista = { @@ -776,6 +788,7 @@ static NO_COPY wincaps wincap_vista = { has_fileid_dirinfo:true, has_exclusiveaddruse:true, has_buggy_restart_scan:false, + needs_count_in_si_lpres2:true, }; wincapc wincap __attribute__((section (".cygwin_dll_common"), shared)); diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h index bbd58a6..f9b86a7 100644 --- a/winsup/cygwin/wincap.h +++ b/winsup/cygwin/wincap.h @@ -69,6 +69,7 @@ struct wincaps unsigned has_fileid_dirinfo : 1; unsigned has_exclusiveaddruse : 1; unsigned has_buggy_restart_scan : 1; + unsigned needs_count_in_si_lpres2 : 1; }; class wincapc @@ -144,6 +145,7 @@ public: bool IMPLEMENT (has_fileid_dirinfo) bool IMPLEMENT (has_exclusiveaddruse) bool IMPLEMENT (has_buggy_restart_scan) + bool IMPLEMENT (needs_count_in_si_lpres2) #undef IMPLEMENT }; |