mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 23:34:52 +02:00
8223777: In posix_spawn mode, failing to exec() jspawnhelper does not result in an error
Reviewed-by: rriggs, martin, fweimer
This commit is contained in:
parent
858b7e21d6
commit
d45aa9c1a9
3 changed files with 51 additions and 0 deletions
|
@ -655,6 +655,18 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env,
|
||||||
c->redirectErrorStream = redirectErrorStream;
|
c->redirectErrorStream = redirectErrorStream;
|
||||||
c->mode = mode;
|
c->mode = mode;
|
||||||
|
|
||||||
|
/* In posix_spawn mode, require the child process to signal aliveness
|
||||||
|
* right after it comes up. This is because there are implementations of
|
||||||
|
* posix_spawn() which do not report failed exec()s back to the caller
|
||||||
|
* (e.g. glibc, see JDK-8223777). In those cases, the fork() will have
|
||||||
|
* worked and successfully started the child process, but the exec() will
|
||||||
|
* have failed. There is no way for us to distinguish this from a target
|
||||||
|
* binary just exiting right after start.
|
||||||
|
*
|
||||||
|
* Note that we could do this additional handshake in all modes but for
|
||||||
|
* prudence only do it when it is needed (in posix_spawn mode). */
|
||||||
|
c->sendAlivePing = (mode == MODE_POSIX_SPAWN) ? 1 : 0;
|
||||||
|
|
||||||
resultPid = startChild(env, process, c, phelperpath);
|
resultPid = startChild(env, process, c, phelperpath);
|
||||||
assert(resultPid != 0);
|
assert(resultPid != 0);
|
||||||
|
|
||||||
|
@ -674,6 +686,30 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env,
|
||||||
}
|
}
|
||||||
close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec (childproc.c) */
|
close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec (childproc.c) */
|
||||||
|
|
||||||
|
/* If we expect the child to ping aliveness, wait for it. */
|
||||||
|
if (c->sendAlivePing) {
|
||||||
|
switch(readFully(fail[0], &errnum, sizeof(errnum))) {
|
||||||
|
case 0: /* First exec failed; */
|
||||||
|
waitpid(resultPid, NULL, 0);
|
||||||
|
throwIOException(env, 0, "Failed to exec spawn helper.");
|
||||||
|
goto Catch;
|
||||||
|
case sizeof(errnum):
|
||||||
|
assert(errnum == CHILD_IS_ALIVE);
|
||||||
|
if (errnum != CHILD_IS_ALIVE) {
|
||||||
|
/* Should never happen since the first thing the spawn
|
||||||
|
* helper should do is to send an alive ping to the parent,
|
||||||
|
* before doing any subsequent work. */
|
||||||
|
throwIOException(env, 0, "Bad code from spawn helper "
|
||||||
|
"(Failed to exec spawn helper.");
|
||||||
|
goto Catch;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throwIOException(env, errno, "Read failed");
|
||||||
|
goto Catch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (readFully(fail[0], &errnum, sizeof(errnum))) {
|
switch (readFully(fail[0], &errnum, sizeof(errnum))) {
|
||||||
case 0: break; /* Exec succeeded */
|
case 0: break; /* Exec succeeded */
|
||||||
case sizeof(errnum):
|
case sizeof(errnum):
|
||||||
|
|
|
@ -315,6 +315,13 @@ childProcess(void *arg)
|
||||||
const ChildStuff* p = (const ChildStuff*) arg;
|
const ChildStuff* p = (const ChildStuff*) arg;
|
||||||
int fail_pipe_fd = p->fail[1];
|
int fail_pipe_fd = p->fail[1];
|
||||||
|
|
||||||
|
if (p->sendAlivePing) {
|
||||||
|
/* Child shall signal aliveness to parent at the very first
|
||||||
|
* moment. */
|
||||||
|
int code = CHILD_IS_ALIVE;
|
||||||
|
restartableWrite(fail_pipe_fd, &code, sizeof(code));
|
||||||
|
}
|
||||||
|
|
||||||
/* Close the parent sides of the pipes.
|
/* Close the parent sides of the pipes.
|
||||||
Closing pipe fds here is redundant, since closeDescriptors()
|
Closing pipe fds here is redundant, since closeDescriptors()
|
||||||
would do it anyways, but a little paranoia is a good thing. */
|
would do it anyways, but a little paranoia is a good thing. */
|
||||||
|
|
|
@ -101,6 +101,7 @@ typedef struct _ChildStuff
|
||||||
const char **envv;
|
const char **envv;
|
||||||
const char *pdir;
|
const char *pdir;
|
||||||
int redirectErrorStream;
|
int redirectErrorStream;
|
||||||
|
int sendAlivePing;
|
||||||
} ChildStuff;
|
} ChildStuff;
|
||||||
|
|
||||||
/* following used in addition when mode is SPAWN */
|
/* following used in addition when mode is SPAWN */
|
||||||
|
@ -114,6 +115,13 @@ typedef struct _SpawnInfo {
|
||||||
int parentPathvBytes; /* total number of bytes in parentPathv array */
|
int parentPathvBytes; /* total number of bytes in parentPathv array */
|
||||||
} SpawnInfo;
|
} SpawnInfo;
|
||||||
|
|
||||||
|
/* If ChildStuff.sendAlivePing is true, child shall signal aliveness to
|
||||||
|
* the parent the moment it gains consciousness, before any subsequent
|
||||||
|
* pre-exec errors could happen.
|
||||||
|
* This code must fit into an int and not be a valid errno value on any of
|
||||||
|
* our platforms. */
|
||||||
|
#define CHILD_IS_ALIVE 65535
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The cached and split version of the JDK's effective PATH.
|
* The cached and split version of the JDK's effective PATH.
|
||||||
* (We don't support putenv("PATH=...") in native code)
|
* (We don't support putenv("PATH=...") in native code)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue