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....