* child_info.h (child_info::sync): Pass pid and HANDLE rather than using pinfo.

(child_info::child_info): Accept an argument controlling whether to create
proc_subproc.
(child_info_spawn::child_info_spawn): Ditto.
* sigproc.cc (child_info::child_info): Ditto.
(child_info_spawn::child_info_spawn): Ditto.
(child_info::sync): Use passed in pid and HANDLE.
* fork.cc (fork_parent): Reflect additional arguments required for
child_info::sync.
* hookapi.cc (hook_or_detect_cygwin): Rename.  Change so that NULL 'fn'
argument just returns "true", indicating that program uses cygwin1.dll.
* spawn.cc (av::win16_exe): New element.
* spawn.cc (av::iscygwin): New element.
(av::fixup): New function.
(spawn_guts): Protect against SEGV.  Use fixup function to detect when it is
safe to wait for a spawned (as opposed to an execed) program.  Reflect changes
in child_info::sync arguments.
* external.cc (cygwin_internal): Reflect function renaming to
hook_or_detect_cygwin.
* cygheap.cc (cygheap_fixup_in_child): Close handle after debug fixup has been
done to prevent false positives in handle collision.
* exceptions.cc (try_to_debug): Notify debugger if already being debugged.
This commit is contained in:
Christopher Faylor 2005-07-17 00:51:03 +00:00
parent cd929277d6
commit e8454a3400
10 changed files with 195 additions and 136 deletions

View File

@ -1,3 +1,32 @@
2005-07-16 Christopher Faylor <cgf@timesys.com>
* child_info.h (child_info::sync): Pass pid and HANDLE rather than
using pinfo.
(child_info::child_info): Accept an argument controlling whether to
create proc_subproc.
(child_info_spawn::child_info_spawn): Ditto.
* sigproc.cc (child_info::child_info): Ditto.
(child_info_spawn::child_info_spawn): Ditto.
(child_info::sync): Use passed in pid and HANDLE.
* fork.cc (fork_parent): Reflect additional arguments required for
child_info::sync.
* hookapi.cc (hook_or_detect_cygwin): Rename. Change so that NULL 'fn'
argument just returns "true", indicating that program uses cygwin1.dll.
* spawn.cc (av::win16_exe): New element.
* spawn.cc (av::iscygwin): New element.
(av::fixup): New function.
(spawn_guts): Protect against SEGV. Use fixup function to detect when
it is safe to wait for a spawned (as opposed to an execed) program.
Reflect changes in child_info::sync arguments.
* external.cc (cygwin_internal): Reflect function renaming to
hook_or_detect_cygwin.
* cygheap.cc (cygheap_fixup_in_child): Close handle after debug fixup
has been done to prevent false positives in handle collision.
* exceptions.cc (try_to_debug): Notify debugger if already being
debugged.
2005-07-09 Christopher Faylor <cgf@timesys.com>
* path.cc (mount): Only check win32_path when we know we need it.
@ -47,6 +76,7 @@
(handler_dev_raw::close): Ditto.
(fhandler_dev_clipboard::fixup_after_exec): New method.
* fhandler_dev_mem.cc (fhandler_dev_mem::close): Eliminate pass through
function in favor of virtual method.
* fhandler_dev_raw.cc (fhandler_dev_raw::close): Ditto.
* fhandler_clipboard.cc (fhandler_dev_clipboard::close): Don't go to
extra effort when execing.
@ -55,8 +85,8 @@
when we know we're execing.
* fhandler_disk_file.cc (fhandler_disk_file::close): Ditto.
* fhandler_dsp.cc (fhandler_dev_dsp::close): Ditto.
* fhandler_fifo.cc (fhandler_fifo.cc::close): Ditto.
function in favor of base function.
* fhandler_fifo.cc (fhandler_fifo.cc::close): Ditto. function in favor
of base function.
* fhandler_random.cc (fhandler_dev_random::close): Ditto.
* fhandler_registry.cc (fhandler_registry::close): Ditto.
* fhandler_tty.cc (fhandler_tty_slave::close): Ditto.

View File

@ -29,7 +29,7 @@ enum child_info_types
#define EXEC_MAGIC_SIZE sizeof(child_info)
#define CURR_CHILD_INFO_MAGIC 0xd94c588aU
#define CURR_CHILD_INFO_MAGIC 0x5eecb012U
/* NOTE: Do not make gratuitous changes to the names or organization of the
below class. The layout is checksummed to determine compatibility between
@ -50,10 +50,10 @@ public:
DWORD cygheap_reserve_sz;
DWORD dwProcessId;
unsigned fhandler_union_cb;
child_info (unsigned, child_info_types);
child_info (unsigned, child_info_types, bool);
~child_info ();
void ready (bool);
bool sync (pinfo&, DWORD);
bool sync (int, HANDLE, DWORD) __attribute__ ((regparm (3)));
};
class mount_info;
@ -104,7 +104,7 @@ public:
cfree (moreinfo);
}
}
child_info_spawn (child_info_types);
child_info_spawn (child_info_types, bool);
};
void __stdcall init_child_info (DWORD, child_info *, HANDLE);

View File

@ -51,7 +51,7 @@ extern "C" {
static void __stdcall _cfree (void *) __attribute__((regparm(1)));
static void *__stdcall _csbrk (int);
}
/* Called by fork or spawn to reallocate cygwin heap */
void __stdcall
cygheap_fixup_in_child (bool execed)
@ -60,13 +60,16 @@ cygheap_fixup_in_child (bool execed)
cygheap = (init_cygheap *) cygheap_max;
_csbrk ((char *) child_proc_info->cygheap_max - (char *) cygheap);
child_copy (child_proc_info->parent, child_proc_info->dwProcessId, "cygheap", cygheap, cygheap_max);
cygheap_init ();
debug_fixup_after_fork_exec ();
/* Need to do this after debug_fixup_after_fork_exec or DEBUGGING handling of
handles might get confused. */
if (execed)
{
CloseHandle (child_proc_info->parent);
child_proc_info->parent = NULL;
}
cygheap_init ();
debug_fixup_after_fork_exec ();
if (execed)
{

View File

@ -320,8 +320,13 @@ extern "C" int
try_to_debug (bool waitloop)
{
debug_printf ("debugger_command '%s'", debugger_command);
if (*debugger_command == '\0' || being_debugged ())
if (*debugger_command == '\0')
return 0;
if (being_debugged ())
{
DebugBreak ();
return 0;
}
__small_sprintf (strchr (debugger_command, '\0'), " %u", GetCurrentProcessId ());

View File

@ -29,7 +29,6 @@ details. */
#include "cygtls.h"
#include "child_info.h"
void *hook_cygwin (const char *, const void *);
child_info *get_cygwin_startup_info ();
static winpids pids;
@ -295,7 +294,7 @@ cygwin_internal (cygwin_getinfo_types t, ...)
{
const char *name = va_arg (arg, const char *);
const void *hookfn = va_arg (arg, const void *);
return (unsigned long) hook_cygwin (name, hookfn);
return (unsigned long) hook_or_detect_cygwin (name, hookfn);
}
case CW_ARGV:
{

View File

@ -414,7 +414,7 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_
#endif
/* Wait for subproc to initialize itself. */
if (!ch.sync (child, FORK_WAIT_TIMEOUT))
if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT))
{
system_printf ("child %d died waiting for longjmp before initialization", child_pid);
goto cleanup;
@ -465,7 +465,7 @@ fork_parent (HANDLE&, dll *&first_dll, bool& load_dlls, void *stack_here, child_
/* Start thread, and wait for it to reload dlls. */
if (!resume_child (forker_finished))
goto cleanup;
else if (!ch.sync (child, FORK_WAIT_TIMEOUT))
else if (!ch.sync (child->pid, pi.hProcess, FORK_WAIT_TIMEOUT))
{
system_printf ("child %d died waiting for dll loading", child_pid);
goto cleanup;

View File

@ -150,7 +150,7 @@ makename (const char *name, char *&buf, int& i, int inc)
// Top level routine to find the EXE's imports, and redirect them
void *
hook_cygwin (const char *name, const void *fn)
hook_or_detect_cygwin (const char *name, const void *fn)
{
HMODULE hm = GetModuleHandle (NULL);
PIMAGE_NT_HEADERS pExeNTHdr = PEHeaderFromHModule (hm);
@ -170,16 +170,19 @@ hook_cygwin (const char *name, const void *fn)
fh.origfn = NULL;
fh.hookfn = fn;
char *buf = (char *) alloca (strlen (name) + strlen ("64") + sizeof ("_"));
int i = -1;
while (!fh.origfn && (fh.name = makename (name, buf, i, 1)))
int i;
// Iterate through each import descriptor, and redirect if appropriate
for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
{
// Iterate through each import descriptor, and redirect if appropriate
for (PIMAGE_IMPORT_DESCRIPTOR pd = pdfirst; pd->FirstThunk; pd++)
{
PSTR modname = rva (PSTR, hm, pd->Name);
if (strcasematch (modname, "cygwin1.dll"))
RedirectIAT (fh, pd, hm);
}
if (!strcasematch (rva (PSTR, hm, pd->Name), "cygwin1.dll"))
continue;
if (!fn)
return (void *) "found it"; // just checking if executable used cygwin1.dll
i = -1;
while (!fh.origfn && (fh.name = makename (name, buf, i, 1)))
RedirectIAT (fh, pd, hm);
if (fh.origfn)
break;
}
while (!fh.origfn && (fh.name = makename (name, buf, i, -1)))

View File

@ -721,7 +721,7 @@ out:
/* Initialize some of the memory block passed to child processes
by fork/spawn/exec. */
child_info::child_info (unsigned in_cb, child_info_types chtype)
child_info::child_info (unsigned in_cb, child_info_types chtype, bool need_subproc_ready)
{
memset (this, 0, in_cb);
cb = in_cb;
@ -730,7 +730,7 @@ child_info::child_info (unsigned in_cb, child_info_types chtype)
type = chtype;
fhandler_union_cb = sizeof (fhandler_union);
user_h = cygwin_user_h;
if (chtype != PROC_SPAWN)
if (need_subproc_ready)
subproc_ready = CreateEvent (&sec_all, FALSE, FALSE, NULL);
sigproc_printf ("subproc_ready %p", subproc_ready);
cygheap = ::cygheap;
@ -753,12 +753,12 @@ child_info::~child_info ()
}
child_info_fork::child_info_fork () :
child_info (sizeof *this, _PROC_FORK)
child_info (sizeof *this, _PROC_FORK, true)
{
}
child_info_spawn::child_info_spawn (child_info_types chtype) :
child_info (sizeof *this, chtype)
child_info_spawn::child_info_spawn (child_info_types chtype, bool need_subproc_ready) :
child_info (sizeof *this, chtype, need_subproc_ready)
{
}
@ -786,7 +786,7 @@ child_info::ready (bool execed)
}
bool
child_info::sync (pinfo& vchild, DWORD howlong)
child_info::sync (pid_t pid, HANDLE hProcess, DWORD howlong)
{
if (!subproc_ready)
{
@ -796,14 +796,14 @@ child_info::sync (pinfo& vchild, DWORD howlong)
HANDLE w4[2];
w4[0] = subproc_ready;
w4[1] = vchild.hProcess;
w4[1] = hProcess;
bool res;
sigproc_printf ("waiting for subproc_ready(%p) and child process(%p)", w4[0], w4[1]);
switch (WaitForMultipleObjects (2, w4, FALSE, howlong))
{
case WAIT_OBJECT_0:
sigproc_printf ("got subproc_ready for pid %d", vchild->pid);
sigproc_printf ("got subproc_ready for pid %d", pid);
res = true;
break;
case WAIT_OBJECT_0 + 1:
@ -813,7 +813,7 @@ child_info::sync (pinfo& vchild, DWORD howlong)
res = false;
break;
default:
system_printf ("wait failed, pid %d, %E", vchild->pid);
system_printf ("wait failed, pid %d, %E", pid);
res = false;
break;
}

View File

@ -32,7 +32,7 @@ details. */
#include "pinfo.h"
#include "registry.h"
#include "environ.h"
#include "cygthread.h"
#include "cygtls.h"
#define LINE_BUF_CHUNK (CYG_MAX_PATH * 2)
@ -264,7 +264,9 @@ class av
public:
int error;
int argc;
av (int ac, const char * const *av) : calloced (0), error (false), argc (ac)
bool win16_exe;
bool iscygwin;
av (int ac, const char * const *av) : calloced (0), error (false), argc (ac), win16_exe (false), iscygwin (true)
{
argv = (char **) cmalloc (HEAP_1_ARGV, (argc + 5) * sizeof (char *));
memcpy (argv, av, (argc + 1) * sizeof (char *));
@ -303,6 +305,7 @@ class av
if (!(argv[i] = cstrdup1 (argv[i])))
error = errno;
}
int fixup (child_info_types, const char *, path_conv&, const char *);
};
int
@ -360,8 +363,6 @@ spawn_guts (const char * prog_arg, const char *const *argv,
bool rc;
pid_t cygpid;
MALLOC_CHECK;
if (prog_arg == NULL)
{
syscall_printf ("prog_arg is NULL");
@ -400,9 +401,12 @@ spawn_guts (const char * prog_arg, const char *const *argv,
for (ac = 0; argv[ac]; ac++)
/* nothing */;
myfault efault;
if (efault.faulted (EFAULT))
return -1; // FIXME: Could be very leaky
av newargv (ac, argv);
bool win16_exe = false;
int null_app_name = 0;
if (ac == 3 && argv[1][0] == '/' && argv[1][1] == 'c' &&
(iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe")))
@ -431,100 +435,10 @@ spawn_guts (const char * prog_arg, const char *const *argv,
}
MALLOC_CHECK;
/* If the file name ends in either .exe, .com, .bat, or .cmd we assume
that it is NOT a script file */
while (*ext == '\0' || (wincap.detect_win16_exe () && strcasematch (ext, ".exe")))
{
HANDLE hnd = CreateFile (real_path, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sec_none_nih, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
if (hnd == INVALID_HANDLE_VALUE)
{
__seterrno ();
return -1;
}
DWORD done;
char buf[2 * CYG_MAX_PATH];
buf[0] = buf[1] = buf[2] = buf[sizeof (buf) - 1] = '\0';
if (!ReadFile (hnd, buf, sizeof (buf) - 1, &done, 0))
{
CloseHandle (hnd);
__seterrno ();
return -1;
}
CloseHandle (hnd);
if (buf[0] == 'M' && buf[1] == 'Z')
{
unsigned off = (unsigned char) buf[0x18] | (((unsigned char) buf[0x19]) << 8);
win16_exe = off < sizeof (IMAGE_DOS_HEADER);
break;
}
debug_printf ("%s is a script", (char *) real_path);
if (real_path.has_acls () && allow_ntsec
&& check_file_access (real_path, X_OK))
{
debug_printf ("... but not executable");
break;
}
char *pgm, *arg1;
if (buf[0] != '#' || buf[1] != '!')
{
pgm = (char *) "/bin/sh";
arg1 = NULL;
}
else
{
char *ptr;
pgm = buf + 2;
pgm += strspn (pgm, " \t");
for (ptr = pgm, arg1 = NULL;
*ptr && *ptr != '\r' && *ptr != '\n';
ptr++)
if (!arg1 && (*ptr == ' ' || *ptr == '\t'))
{
/* Null terminate the initial command and step over
any additional white space. If we've hit the
end of the line, exit the loop. Otherwise, we've
found the first argument. Position the current
pointer on the last known white space. */
*ptr = '\0';
char *newptr = ptr + 1;
newptr += strspn (newptr, " \t");
if (!*newptr || *newptr == '\r' || *newptr == '\n')
break;
arg1 = newptr;
ptr = newptr - 1;
}
*ptr = '\0';
}
/* Replace argv[0] with the full path to the script if this is the
first time through the loop. */
newargv.replace0_maybe (prog_arg);
/* pointers:
* pgm interpreter name
* arg1 optional string
*/
if (arg1)
newargv.unshift (arg1);
/* FIXME: This should not be using FE_NATIVE. It should be putting
the posix path on the argv list. */
find_exec (pgm, real_path, "PATH=", FE_NATIVE, &ext);
newargv.unshift (real_path, 1);
}
int res;
res = newargv.fixup (chtype, prog_arg, real_path, ext);
if (res)
return res;
if (real_path.iscygexec ())
newargv.dup_all ();
@ -672,7 +586,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
cygheap->user.deimpersonate ();
moreinfo->envp = build_env (envp, envblock, moreinfo->envc, real_path.iscygexec ());
child_info_spawn ciresrv (chtype);
child_info_spawn ciresrv (chtype, newargv.iscygwin);
ciresrv.moreinfo = moreinfo;
si.lpReserved2 = (LPBYTE) &ciresrv;
@ -763,7 +677,6 @@ spawn_guts (const char * prog_arg, const char *const *argv,
/* FIXME: There is a small race here */
int res;
pthread_cleanup cleanup;
if (mode == _P_SYSTEM)
{
@ -794,6 +707,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
ProtectHandle1 (pi.hProcess, childhProc);
bool synced;
pid_t pid;
if (mode == _P_OVERLAY)
{
myself->dwProcessId = dwExeced = pi.dwProcessId;
@ -813,7 +727,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
on this fact when we exit. dup_proc_pipe will close our end of the pipe.
Note that wr_proc_pipe may also be == INVALID_HANDLE_VALUE. That will make
dup_proc_pipe essentially a no-op. */
if (!win16_exe && myself->wr_proc_pipe)
if (!newargv.win16_exe && myself->wr_proc_pipe)
{
myself->sync_proc_pipe (); /* Make sure that we own wr_proc_pipe
just in case we've been previously
@ -821,6 +735,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
myself.zap_cwd ();
myself->dup_proc_pipe (pi.hProcess);
}
pid = myself->pid;
}
else
{
@ -856,6 +771,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
res = -1;
goto out;
}
pid = child->pid;
}
/* Start the child running */
@ -865,7 +781,7 @@ spawn_guts (const char * prog_arg, const char *const *argv,
sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
synced = ciresrv.sync (myself, INFINITE);
synced = ciresrv.sync (pid, pi.hProcess, INFINITE);
switch (mode)
{
@ -1075,3 +991,104 @@ spawnvpe (int mode, const char *file, const char * const *argv,
path_conv buf;
return spawnve (mode, find_exec (file, buf), argv, envp);
}
int
av::fixup (child_info_types chtype, const char *prog_arg, path_conv& real_path, const char *ext)
{
/* If the file name ends in either .exe, .com, .bat, or .cmd we assume
that it is NOT a script file */
while (*ext == '\0' || chtype == PROC_SPAWN || (wincap.detect_win16_exe () && strcasematch (ext, ".exe")))
{
HANDLE h = CreateFile (real_path, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
&sec_none_nih, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
if (h == INVALID_HANDLE_VALUE)
goto err;
HANDLE hm = CreateFileMapping (h, &sec_none_nih, PAGE_READONLY, 0, 0, NULL);
CloseHandle (h);
if (!hm)
goto err;
char *buf = (char *) MapViewOfFile(hm, FILE_MAP_READ, 0, 0, 0);
CloseHandle (hm);
if (!buf)
goto err;
if (buf[0] == 'M' && buf[1] == 'Z')
{
unsigned off = (unsigned char) buf[0x18] | (((unsigned char) buf[0x19]) << 8);
win16_exe = off < sizeof (IMAGE_DOS_HEADER);
if (!win16_exe)
iscygwin = hook_or_detect_cygwin (buf, NULL);
UnmapViewOfFile (buf);
break;
}
debug_printf ("%s is a script", (char *) real_path);
if (real_path.has_acls () && allow_ntsec
&& check_file_access (real_path, X_OK))
{
debug_printf ("... but not executable");
break;
}
char *pgm = NULL;
char *arg1 = NULL;
char *ptr = buf;
if (*ptr++ == '#' && *ptr++ == '!')
{
ptr += strspn (ptr, " \t");
size_t len = strcspn (ptr, "\r\n");
if (len)
{
char *namebuf = (char *) alloca (len + 1);
memcpy (namebuf, ptr, len);
namebuf[len] = '\0';
for (ptr = pgm = namebuf; *ptr; ptr++)
if (!arg1 && (*ptr == ' ' || *ptr == '\t'))
{
/* Null terminate the initial command and step over any additional white
space. If we've hit the end of the line, exit the loop. Otherwise,
we've found the first argument. Position the current pointer on the
last known white space. */
*ptr = '\0';
char *newptr = ptr + 1;
newptr += strspn (newptr, " \t");
if (!*newptr)
break;
arg1 = newptr;
ptr = newptr - 1;
}
}
}
UnmapViewOfFile (buf);
if (!pgm)
{
pgm = (char *) "/bin/sh";
arg1 = NULL;
}
/* Replace argv[0] with the full path to the script if this is the
first time through the loop. */
replace0_maybe (prog_arg);
/* pointers:
* pgm interpreter name
* arg1 optional string
*/
if (arg1)
unshift (arg1);
/* FIXME: This should not be using FE_NATIVE. It should be putting
the posix path on the argv list. */
find_exec (pgm, real_path, "PATH=", FE_NATIVE, &ext);
unshift (real_path, 1);
}
return 0;
err:
__seterrno ();
return -1;
}

View File

@ -255,6 +255,8 @@ extern "C" int __stdcall strcasematch (const char *s1, const char *s2) __attribu
extern "C" int __stdcall strncasematch (const char *s1, const char *s2, size_t n) __attribute__ ((regparm(3)));
extern "C" char *__stdcall strcasestr (const char *searchee, const char *lookfor) __attribute__ ((regparm(2)));
void *hook_or_detect_cygwin (const char *, const void *) __attribute__ ((regparm (2)));
/* Time related */
void __stdcall totimeval (struct timeval *, FILETIME *, int, int);
long __stdcall to_time_t (FILETIME *);