aboutsummaryrefslogtreecommitdiff
path: root/winsup
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2006-12-05 11:34:01 +0000
committerCorinna Vinschen <corinna@vinschen.de>2006-12-05 11:34:01 +0000
commit2c36d592bace7c87156c974b119f5338b917f36b (patch)
tree2ece4959bcf923a89db8da1eb19506543896b2a1 /winsup
parent20d4425edbaf65daa59428ba5386370cacac307e (diff)
downloadnewlib-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/ChangeLog12
-rw-r--r--winsup/cygwin/dcrt0.cc28
-rw-r--r--winsup/cygwin/fork.cc5
-rw-r--r--winsup/cygwin/spawn.cc13
-rw-r--r--winsup/cygwin/wincap.cc13
-rw-r--r--winsup/cygwin/wincap.h2
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
};