45 msgRe: Something is broken in repack
2 msg$prefix/lib/../$target/sys-include not in <&...
1 msggcc-4.1-20071210 is now available
1 msgClarification on section variable attribute usa...
1 msgAlias-analysis in gccint
1 msglibiberty: make install doesn't install obstack...
3 msgUsing -mlittle-endian or -mbig-endian options....
3 msgInserting arbitrary GIMPLE statements & ali...
2 msgRegarding
6 msgRevisiting GCC's minimum MPFR version
1 msgFwd: Cross compiler build stops
14 msgHelp with another constraint
5 msgVLIW scheduling and delayed branch
3 msgThe Regents of the University of California BSD...
1 msgWhere was gone?
2 msgHowto make another convertion with _identifiers...
1 msggcc-4.3-20071207 is now available
3 msgRe: BITS_PER_UNIT less than 8
1 msgBroken link for Modula-3 front end.

libiberty/pex-unix vfork abuse?
\ Dave Korn (7 Dec 2007)
. \ Ian Lance Taylor (7 Dec 2007)
. . \ Dave Korn (7 Dec 2007)
. . . \ Ian Lance Taylor (7 Dec 2007)
. . . \ Andreas Schwab (7 Dec 2007)
. . . . \ Dave Korn (10 Dec 2007)
. . . . . \ Joe Buck (10 Dec 2007)
. . . . . . \ Daniel Jacobowitz (10 Dec 2007)
. . . . . . . \ Joe Buck (10 Dec 2007)
. . . . . . . \ Andreas Schwab (10 Dec 2007)
. . . . . . . . \ Daniel Jacobowitz (10 Dec 2007)
. . . . . . \ Ian Lance Taylor (10 Dec 2007)
. . . . . . \ Andreas Schwab (10 Dec 2007)
. . . . . \ Andreas Schwab (10 Dec 2007)
. \ J.C. Pizarro (7 Dec 2007)
. . \ Dave Korn (7 Dec 2007)
. . . \ Joe Buck (7 Dec 2007)
. . . . \ J.C. Pizarro (7 Dec 2007)
. . . . . \ Andrew Haley (7 Dec 2007)
. . . . . \ Dave Korn (7 Dec 2007)
. . . . . . \ J.C. Pizarro (7 Dec 2007)
. . . . . \ Diego Novillo (7 Dec 2007)
. . . . . \ Gabriel Dos Reis (7 Dec 2007)
. \ (Ross Ridge) (7 Dec 2007)
. \ Brian Dessent (10 Dec 2007)
. . \ Dave Korn (10 Dec 2007)

Subject:libiberty/pex-unix vfork abuse?
Group:Gcc
From:Dave Korn
Date:7 Dec 2007



Hey all,

This is what posix says about vfork:

http://www.opengroup.org/onlinepubs/000095399/functions/vfork.html
"The vfork() function shall be equivalent to fork(), except that the behavior
is undefined if the process created by vfork() either modifies any data other
than a variable of type pid_t used to store the return value from vfork(), or
returns from the function in which vfork() was called, or calls any other
function before successfully calling _exit() or one of the exec family of
functions."

This is how pex-unix.c uses vfork:

static long
pex_unix_exec_child (struct pex_obj *obj, int flags, const char *executable,
char * const * argv, char * const * env,
int in, int out, int errdes,
int toclose, const char **errmsg, int *err)
{
pid_t pid;

/* We declare these to be volatile to avoid warnings from gcc about
them being clobbered by vfork. */
volatile int sleep_interval;
volatile int retries;

sleep_interval = 1;
pid = -1;
for (retries = 0; retries < 4; ++retries)
{
pid = vfork ();
if (pid >= 0)
break;
sleep (sleep_interval);
sleep_interval *= 2;
}

switch (pid)
{
case -1:
*err = errno;
*errmsg = VFORK_STRING;
return -1;

case 0:
/* Child process. */
if (in != STDIN_FILE_NO)
{
if (dup2 (in, STDIN_FILE_NO) < 0)
pex_child_error (obj, executable, "dup2", errno);
if (close (in) < 0)
pex_child_error (obj, executable, "close", errno);
}
if (out != STDOUT_FILE_NO)
{
if (dup2 (out, STDOUT_FILE_NO) < 0)
pex_child_error (obj, executable, "dup2", errno);
if (close (out) < 0)
pex_child_error (obj, executable, "close", errno);
}
if (errdes != STDERR_FILE_NO)
{
if (dup2 (errdes, STDERR_FILE_NO) < 0)
pex_child_error (obj, executable, "dup2", errno);
if (close (errdes) < 0)
pex_child_error (obj, executable, "close", errno);
}
if (toclose >= 0)
{
if (close (toclose) < 0)
pex_child_error (obj, executable, "close", errno);
}
if ((flags & PEX_STDERR_TO_STDOUT) != 0)
{
if (dup2 (STDOUT_FILE_NO, STDERR_FILE_NO) < 0)
pex_child_error (obj, executable, "dup2", errno);
}

if (env)
environ = (char**) env;

if ((flags & PEX_SEARCH) != 0)
{
execvp (executable, argv);
pex_child_error (obj, executable, "execvp", errno);
}
else
{
execv (executable, argv);
pex_child_error (obj, executable, "execv", errno);
}



Note the several calls to dup2() and close(), which seem to me to be "calls
[to] any other function", and the setting of environ, which seem to me to be
modification of "any data other than a variable of type pid_t used to store
the return value from vfork()". The comment on pex_child_error (which uses
write() to do output) gives a hint at the thinking here:


/* Report an error from a child process. We don't use stdio routines,
because we might be here due to a vfork call. */

static void
pex_child_error (struct pex_obj *obj, const char *executable,
const char *errmsg, int err)
{
#define writeerr(s) (void) write (STDERR_FILE_NO, s, strlen (s))
writeerr (obj->pname);


But I don't see any reason to assume the restriction only applies to f*()
stdio functions, in fact by my reading I don't think you're [technically] even
allowed to call a pure const inline function that's part of your own code. (I
assume that that would in fact work ok in practice at least most of the time).

Are we ok here? This code seems like it's doing the wrong thing to me. As
far as I can tell, we only get away with this in cygwin because of paranoid
defensive programming that backs up the fd table before running the vfork'd
child's code in the parent's context up to the first exec*() call, and then
restores it afterward, but I'm fairly sure that this implementation will still
overwrite the parent's environment.... which could well be Not A Good Thing!


cheers,
DaveK
--
Can't think of a witty .sigline today....



© 2004-2008 readlist.com