653 copyPipe(childenv, c->childenv); |
653 copyPipe(childenv, c->childenv); |
654 |
654 |
655 c->redirectErrorStream = redirectErrorStream; |
655 c->redirectErrorStream = redirectErrorStream; |
656 c->mode = mode; |
656 c->mode = mode; |
657 |
657 |
|
658 /* In posix_spawn mode, require the child process to signal aliveness |
|
659 * right after it comes up. This is because there are implementations of |
|
660 * posix_spawn() which do not report failed exec()s back to the caller |
|
661 * (e.g. glibc, see JDK-8223777). In those cases, the fork() will have |
|
662 * worked and successfully started the child process, but the exec() will |
|
663 * have failed. There is no way for us to distinguish this from a target |
|
664 * binary just exiting right after start. |
|
665 * |
|
666 * Note that we could do this additional handshake in all modes but for |
|
667 * prudence only do it when it is needed (in posix_spawn mode). */ |
|
668 c->sendAlivePing = (mode == MODE_POSIX_SPAWN) ? 1 : 0; |
|
669 |
658 resultPid = startChild(env, process, c, phelperpath); |
670 resultPid = startChild(env, process, c, phelperpath); |
659 assert(resultPid != 0); |
671 assert(resultPid != 0); |
660 |
672 |
661 if (resultPid < 0) { |
673 if (resultPid < 0) { |
662 switch (c->mode) { |
674 switch (c->mode) { |
672 } |
684 } |
673 goto Catch; |
685 goto Catch; |
674 } |
686 } |
675 close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec (childproc.c) */ |
687 close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec (childproc.c) */ |
676 |
688 |
|
689 /* If we expect the child to ping aliveness, wait for it. */ |
|
690 if (c->sendAlivePing) { |
|
691 switch(readFully(fail[0], &errnum, sizeof(errnum))) { |
|
692 case 0: /* First exec failed; */ |
|
693 waitpid(resultPid, NULL, 0); |
|
694 throwIOException(env, 0, "Failed to exec spawn helper."); |
|
695 goto Catch; |
|
696 case sizeof(errnum): |
|
697 assert(errnum == CHILD_IS_ALIVE); |
|
698 if (errnum != CHILD_IS_ALIVE) { |
|
699 /* Should never happen since the first thing the spawn |
|
700 * helper should do is to send an alive ping to the parent, |
|
701 * before doing any subsequent work. */ |
|
702 throwIOException(env, 0, "Bad code from spawn helper " |
|
703 "(Failed to exec spawn helper."); |
|
704 goto Catch; |
|
705 } |
|
706 break; |
|
707 default: |
|
708 throwIOException(env, errno, "Read failed"); |
|
709 goto Catch; |
|
710 } |
|
711 } |
|
712 |
677 switch (readFully(fail[0], &errnum, sizeof(errnum))) { |
713 switch (readFully(fail[0], &errnum, sizeof(errnum))) { |
678 case 0: break; /* Exec succeeded */ |
714 case 0: break; /* Exec succeeded */ |
679 case sizeof(errnum): |
715 case sizeof(errnum): |
680 waitpid(resultPid, NULL, 0); |
716 waitpid(resultPid, NULL, 0); |
681 throwIOException(env, errnum, "Exec failed"); |
717 throwIOException(env, errnum, "Exec failed"); |