Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/unix/native/libjava/ProcessImpl_md.c
41119 views
1
/*
2
* Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
#undef _LARGEFILE64_SOURCE
27
#define _LARGEFILE64_SOURCE 1
28
29
#include "jni.h"
30
#include "jvm.h"
31
#include "jvm_md.h"
32
#include "jni_util.h"
33
#include "io_util.h"
34
35
/*
36
* Platform-specific support for java.lang.Process
37
*/
38
#include <assert.h>
39
#include <stddef.h>
40
#include <stdlib.h>
41
#include <sys/types.h>
42
#include <ctype.h>
43
#include <sys/wait.h>
44
#include <signal.h>
45
#include <string.h>
46
47
#include <spawn.h>
48
49
#include "childproc.h"
50
51
/*
52
*
53
* When starting a child on Unix, we need to do three things:
54
* - fork off
55
* - in the child process, do some pre-exec work: duping/closing file
56
* descriptors to set up stdio-redirection, setting environment variables,
57
* changing paths...
58
* - then exec(2) the target binary
59
*
60
* There are three ways to fork off:
61
*
62
* A) fork(2). Portable and safe (no side effects) but may fail with ENOMEM on
63
* all Unices when invoked from a VM with a high memory footprint. On Unices
64
* with strict no-overcommit policy this problem is most visible.
65
*
66
* This is because forking the VM will first create a child process with
67
* theoretically the same memory footprint as the parent - even if you plan
68
* to follow up with exec'ing a tiny binary. In reality techniques like
69
* copy-on-write etc mitigate the problem somewhat but we still run the risk
70
* of hitting system limits.
71
*
72
* For a Linux centric description of this problem, see the documentation on
73
* /proc/sys/vm/overcommit_memory in Linux proc(5).
74
*
75
* B) vfork(2): Portable and fast but very unsafe. It bypasses the memory
76
* problems related to fork(2) by starting the child in the memory image of
77
* the parent. Things that can go wrong include:
78
* - Programming errors in the child process before the exec(2) call may
79
* trash memory in the parent process, most commonly the stack of the
80
* thread invoking vfork.
81
* - Signals received by the child before the exec(2) call may be at best
82
* misdirected to the parent, at worst immediately kill child and parent.
83
*
84
* This is mitigated by very strict rules about what one is allowed to do in
85
* the child process between vfork(2) and exec(2), which is basically nothing.
86
* However, we always broke this rule by doing the pre-exec work between
87
* vfork(2) and exec(2).
88
*
89
* Also note that vfork(2) has been deprecated by the OpenGroup, presumably
90
* because of its many dangers.
91
*
92
* C) clone(2): This is a Linux specific call which gives the caller fine
93
* grained control about how exactly the process fork is executed. It is
94
* powerful, but Linux-specific.
95
*
96
* Aside from these three possibilities there is a forth option: posix_spawn(3).
97
* Where fork/vfork/clone all fork off the process and leave pre-exec work and
98
* calling exec(2) to the user, posix_spawn(3) offers the user fork+exec-like
99
* functionality in one package, similar to CreateProcess() on Windows.
100
*
101
* It is not a system call in itself, but usually a wrapper implemented within
102
* the libc in terms of one of (fork|vfork|clone)+exec - so whether or not it
103
* has advantages over calling the naked (fork|vfork|clone) functions depends
104
* on how posix_spawn(3) is implemented.
105
*
106
* Note that when using posix_spawn(3), we exec twice: first a tiny binary called
107
* the jspawnhelper, then in the jspawnhelper we do the pre-exec work and exec a
108
* second time, this time the target binary (similar to the "exec-twice-technique"
109
* described in http://mail.openjdk.java.net/pipermail/core-libs-dev/2018-September/055333.html).
110
*
111
* This is a JDK-specific implementation detail which just happens to be
112
* implemented for jdk.lang.Process.launchMechanism=POSIX_SPAWN.
113
*
114
* --- Linux-specific ---
115
*
116
* How does glibc implement posix_spawn?
117
* (see: sysdeps/posix/spawni.c for glibc < 2.24,
118
* sysdeps/unix/sysv/linux/spawni.c for glibc >= 2.24):
119
*
120
* 1) Before glibc 2.4 (released 2006), posix_spawn(3) used just fork(2)/exec(2).
121
* This would be bad for the JDK since we would risk the known memory issues with
122
* fork(2). But since this only affects glibc variants which have long been
123
* phased out by modern distributions, this is irrelevant.
124
*
125
* 2) Between glibc 2.4 and glibc 2.23, posix_spawn uses either fork(2) or
126
* vfork(2) depending on how exactly the user called posix_spawn(3):
127
*
128
* <quote>
129
* The child process is created using vfork(2) instead of fork(2) when
130
* either of the following is true:
131
*
132
* * the spawn-flags element of the attributes object pointed to by
133
* attrp contains the GNU-specific flag POSIX_SPAWN_USEVFORK; or
134
*
135
* * file_actions is NULL and the spawn-flags element of the attributes
136
* object pointed to by attrp does not contain
137
* POSIX_SPAWN_SETSIGMASK, POSIX_SPAWN_SETSIGDEF,
138
* POSIX_SPAWN_SETSCHEDPARAM, POSIX_SPAWN_SETSCHEDULER,
139
* POSIX_SPAWN_SETPGROUP, or POSIX_SPAWN_RESETIDS.
140
* </quote>
141
*
142
* Due to the way the JDK calls posix_spawn(3), it would therefore call vfork(2).
143
* So we would avoid the fork(2) memory problems. However, there still remains the
144
* risk associated with vfork(2). But it is smaller than were we to call vfork(2)
145
* directly since we use the jspawnhelper, moving all pre-exec work off to after
146
* the first exec, thereby reducing the vulnerable time window.
147
*
148
* 3) Since glibc >= 2.24, glibc uses clone+exec:
149
*
150
* new_pid = CLONE (__spawni_child, STACK (stack, stack_size), stack_size,
151
* CLONE_VM | CLONE_VFORK | SIGCHLD, &args);
152
*
153
* This is even better than (2):
154
*
155
* CLONE_VM means we run in the parent's memory image, as with (2)
156
* CLONE_VFORK means parent waits until we exec, as with (2)
157
*
158
* However, error possibilities are further reduced since:
159
* - posix_spawn(3) passes a separate stack for the child to run on, eliminating
160
* the danger of trashing the forking thread's stack in the parent process.
161
* - posix_spawn(3) takes care to temporarily block all incoming signals to the
162
* child process until the first exec(2) has been called,
163
*
164
* TL;DR
165
* Calling posix_spawn(3) for glibc
166
* (2) < 2.24 is not perfect but still better than using plain vfork(2), since
167
* the chance of an error happening is greatly reduced
168
* (3) >= 2.24 is the best option - portable, fast and as safe as possible.
169
*
170
* ---
171
*
172
* How does muslc implement posix_spawn?
173
*
174
* They always did use the clone (.. CLONE_VM | CLONE_VFORK ...)
175
* technique. So we are safe to use posix_spawn() here regardless of muslc
176
* version.
177
*
178
* </Linux-specific>
179
*
180
*
181
* Based on the above analysis, we are currently defaulting to posix_spawn()
182
* on all Unices including Linux.
183
*/
184
185
static void
186
setSIGCHLDHandler(JNIEnv *env)
187
{
188
/* There is a subtle difference between having the signal handler
189
* for SIGCHLD be SIG_DFL and SIG_IGN. We cannot obtain process
190
* termination information for child processes if the signal
191
* handler is SIG_IGN. It must be SIG_DFL.
192
*
193
* We used to set the SIGCHLD handler only on Linux, but it's
194
* safest to set it unconditionally.
195
*
196
* Consider what happens if java's parent process sets the SIGCHLD
197
* handler to SIG_IGN. Normally signal handlers are inherited by
198
* children, but SIGCHLD is a controversial case. Solaris appears
199
* to always reset it to SIG_DFL, but this behavior may be
200
* non-standard-compliant, and we shouldn't rely on it.
201
*
202
* References:
203
* http://www.opengroup.org/onlinepubs/7908799/xsh/exec.html
204
* http://www.pasc.org/interps/unofficial/db/p1003.1/pasc-1003.1-132.html
205
*/
206
struct sigaction sa;
207
sa.sa_handler = SIG_DFL;
208
sigemptyset(&sa.sa_mask);
209
sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
210
if (sigaction(SIGCHLD, &sa, NULL) < 0)
211
JNU_ThrowInternalError(env, "Can't set SIGCHLD handler");
212
}
213
214
static void*
215
xmalloc(JNIEnv *env, size_t size)
216
{
217
void *p = malloc(size);
218
if (p == NULL)
219
JNU_ThrowOutOfMemoryError(env, NULL);
220
return p;
221
}
222
223
#define NEW(type, n) ((type *) xmalloc(env, (n) * sizeof(type)))
224
225
/**
226
* If PATH is not defined, the OS provides some default value.
227
* Unfortunately, there's no portable way to get this value.
228
* Fortunately, it's only needed if the child has PATH while we do not.
229
*/
230
static const char*
231
defaultPath(void)
232
{
233
return ":/bin:/usr/bin";
234
}
235
236
static const char*
237
effectivePath(void)
238
{
239
const char *s = getenv("PATH");
240
return (s != NULL) ? s : defaultPath();
241
}
242
243
static int
244
countOccurrences(const char *s, char c)
245
{
246
int count;
247
for (count = 0; *s != '\0'; s++)
248
count += (*s == c);
249
return count;
250
}
251
252
static const char * const *
253
effectivePathv(JNIEnv *env)
254
{
255
char *p;
256
int i;
257
const char *path = effectivePath();
258
int count = countOccurrences(path, ':') + 1;
259
size_t pathvsize = sizeof(const char *) * (count+1);
260
size_t pathsize = strlen(path) + 1;
261
const char **pathv = (const char **) xmalloc(env, pathvsize + pathsize);
262
263
if (pathv == NULL)
264
return NULL;
265
p = (char *) pathv + pathvsize;
266
memcpy(p, path, pathsize);
267
/* split PATH by replacing ':' with NULs; empty components => "." */
268
for (i = 0; i < count; i++) {
269
char *q = p + strcspn(p, ":");
270
pathv[i] = (p == q) ? "." : p;
271
*q = '\0';
272
p = q + 1;
273
}
274
pathv[count] = NULL;
275
return pathv;
276
}
277
278
JNIEXPORT void JNICALL
279
Java_java_lang_ProcessImpl_init(JNIEnv *env, jclass clazz)
280
{
281
parentPathv = effectivePathv(env);
282
CHECK_NULL(parentPathv);
283
setSIGCHLDHandler(env);
284
}
285
286
287
#ifndef WIFEXITED
288
#define WIFEXITED(status) (((status)&0xFF) == 0)
289
#endif
290
291
#ifndef WEXITSTATUS
292
#define WEXITSTATUS(status) (((status)>>8)&0xFF)
293
#endif
294
295
#ifndef WIFSIGNALED
296
#define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0)
297
#endif
298
299
#ifndef WTERMSIG
300
#define WTERMSIG(status) ((status)&0x7F)
301
#endif
302
303
static const char *
304
getBytes(JNIEnv *env, jbyteArray arr)
305
{
306
return arr == NULL ? NULL :
307
(const char*) (*env)->GetByteArrayElements(env, arr, NULL);
308
}
309
310
static void
311
releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr)
312
{
313
if (parr != NULL)
314
(*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT);
315
}
316
317
#define IOE_FORMAT "error=%d, %s"
318
319
static void
320
throwIOException(JNIEnv *env, int errnum, const char *defaultDetail)
321
{
322
const char *detail = defaultDetail;
323
char *errmsg;
324
size_t fmtsize;
325
char tmpbuf[1024];
326
jstring s;
327
328
if (errnum != 0) {
329
int ret = getErrorString(errnum, tmpbuf, sizeof(tmpbuf));
330
if (ret != EINVAL)
331
detail = tmpbuf;
332
}
333
/* ASCII Decimal representation uses 2.4 times as many bits as binary. */
334
fmtsize = sizeof(IOE_FORMAT) + strlen(detail) + 3 * sizeof(errnum);
335
errmsg = NEW(char, fmtsize);
336
if (errmsg == NULL)
337
return;
338
339
snprintf(errmsg, fmtsize, IOE_FORMAT, errnum, detail);
340
s = JNU_NewStringPlatform(env, errmsg);
341
if (s != NULL) {
342
jobject x = JNU_NewObjectByName(env, "java/io/IOException",
343
"(Ljava/lang/String;)V", s);
344
if (x != NULL)
345
(*env)->Throw(env, x);
346
}
347
free(errmsg);
348
}
349
350
/**
351
* Throws an IOException with a message composed from the result of waitpid status.
352
*/
353
static void throwExitCause(JNIEnv *env, int pid, int status) {
354
char ebuf[128];
355
if (WIFEXITED(status)) {
356
snprintf(ebuf, sizeof ebuf,
357
"Failed to exec spawn helper: pid: %d, exit value: %d",
358
pid, WEXITSTATUS(status));
359
} else if (WIFSIGNALED(status)) {
360
snprintf(ebuf, sizeof ebuf,
361
"Failed to exec spawn helper: pid: %d, signal: %d",
362
pid, WTERMSIG(status));
363
} else {
364
snprintf(ebuf, sizeof ebuf,
365
"Failed to exec spawn helper: pid: %d, status: 0x%08x",
366
pid, status);
367
}
368
throwIOException(env, 0, ebuf);
369
}
370
371
#ifdef DEBUG_PROCESS
372
/* Debugging process code is difficult; where to write debug output? */
373
static void
374
debugPrint(char *format, ...)
375
{
376
FILE *tty = fopen("/dev/tty", "w");
377
va_list ap;
378
va_start(ap, format);
379
vfprintf(tty, format, ap);
380
va_end(ap);
381
fclose(tty);
382
}
383
#endif /* DEBUG_PROCESS */
384
385
static void
386
copyPipe(int from[2], int to[2])
387
{
388
to[0] = from[0];
389
to[1] = from[1];
390
}
391
392
/* arg is an array of pointers to 0 terminated strings. array is terminated
393
* by a null element.
394
*
395
* *nelems and *nbytes receive the number of elements of array (incl 0)
396
* and total number of bytes (incl. 0)
397
* Note. An empty array will have one null element
398
* But if arg is null, then *nelems set to 0, and *nbytes to 0
399
*/
400
static void arraysize(const char * const *arg, int *nelems, int *nbytes)
401
{
402
int i, bytes, count;
403
const char * const *a = arg;
404
char *p;
405
int *q;
406
if (arg == 0) {
407
*nelems = 0;
408
*nbytes = 0;
409
return;
410
}
411
/* count the array elements and number of bytes */
412
for (count=0, bytes=0; *a != 0; count++, a++) {
413
bytes += strlen(*a)+1;
414
}
415
*nbytes = bytes;
416
*nelems = count+1;
417
}
418
419
/* copy the strings from arg[] into buf, starting at given offset
420
* return new offset to next free byte
421
*/
422
static int copystrings(char *buf, int offset, const char * const *arg) {
423
char *p;
424
const char * const *a;
425
int count=0;
426
427
if (arg == 0) {
428
return offset;
429
}
430
for (p=buf+offset, a=arg; *a != 0; a++) {
431
int len = strlen(*a) +1;
432
memcpy(p, *a, len);
433
p += len;
434
count += len;
435
}
436
return offset+count;
437
}
438
439
/**
440
* We are unusually paranoid; use of vfork is
441
* especially likely to tickle gcc/glibc bugs.
442
*/
443
#ifdef __attribute_noinline__ /* See: sys/cdefs.h */
444
__attribute_noinline__
445
#endif
446
447
/* vfork(2) is deprecated on Solaris */
448
static pid_t
449
vforkChild(ChildStuff *c) {
450
volatile pid_t resultPid;
451
452
/*
453
* We separate the call to vfork into a separate function to make
454
* very sure to keep stack of child from corrupting stack of parent,
455
* as suggested by the scary gcc warning:
456
* warning: variable 'foo' might be clobbered by 'longjmp' or 'vfork'
457
*/
458
resultPid = vfork();
459
460
if (resultPid == 0) {
461
childProcess(c);
462
}
463
assert(resultPid != 0); /* childProcess never returns */
464
return resultPid;
465
}
466
467
static pid_t
468
forkChild(ChildStuff *c) {
469
pid_t resultPid;
470
471
/*
472
* From Solaris fork(2): In Solaris 10, a call to fork() is
473
* identical to a call to fork1(); only the calling thread is
474
* replicated in the child process. This is the POSIX-specified
475
* behavior for fork().
476
*/
477
resultPid = fork();
478
479
if (resultPid == 0) {
480
childProcess(c);
481
}
482
assert(resultPid != 0); /* childProcess never returns */
483
return resultPid;
484
}
485
486
static pid_t
487
spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {
488
pid_t resultPid;
489
jboolean isCopy;
490
int i, offset, rval, bufsize, magic;
491
char *buf, buf1[16];
492
char *hlpargs[2];
493
SpawnInfo sp;
494
495
/* need to tell helper which fd is for receiving the childstuff
496
* and which fd to send response back on
497
*/
498
snprintf(buf1, sizeof(buf1), "%d:%d", c->childenv[0], c->fail[1]);
499
/* put the fd string as argument to the helper cmd */
500
hlpargs[0] = buf1;
501
hlpargs[1] = 0;
502
503
/* Following items are sent down the pipe to the helper
504
* after it is spawned.
505
* All strings are null terminated. All arrays of strings
506
* have an empty string for termination.
507
* - the ChildStuff struct
508
* - the SpawnInfo struct
509
* - the argv strings array
510
* - the envv strings array
511
* - the home directory string
512
* - the parentPath string
513
* - the parentPathv array
514
*/
515
/* First calculate the sizes */
516
arraysize(c->argv, &sp.nargv, &sp.argvBytes);
517
bufsize = sp.argvBytes;
518
arraysize(c->envv, &sp.nenvv, &sp.envvBytes);
519
bufsize += sp.envvBytes;
520
sp.dirlen = c->pdir == 0 ? 0 : strlen(c->pdir)+1;
521
bufsize += sp.dirlen;
522
arraysize(parentPathv, &sp.nparentPathv, &sp.parentPathvBytes);
523
bufsize += sp.parentPathvBytes;
524
/* We need to clear FD_CLOEXEC if set in the fds[].
525
* Files are created FD_CLOEXEC in Java.
526
* Otherwise, they will be closed when the target gets exec'd */
527
for (i=0; i<3; i++) {
528
if (c->fds[i] != -1) {
529
int flags = fcntl(c->fds[i], F_GETFD);
530
if (flags & FD_CLOEXEC) {
531
fcntl(c->fds[i], F_SETFD, flags & (~1));
532
}
533
}
534
}
535
536
rval = posix_spawn(&resultPid, helperpath, 0, 0, (char * const *) hlpargs, environ);
537
538
if (rval != 0) {
539
return -1;
540
}
541
542
/* now the lengths are known, copy the data */
543
buf = NEW(char, bufsize);
544
if (buf == 0) {
545
return -1;
546
}
547
offset = copystrings(buf, 0, &c->argv[0]);
548
offset = copystrings(buf, offset, &c->envv[0]);
549
memcpy(buf+offset, c->pdir, sp.dirlen);
550
offset += sp.dirlen;
551
offset = copystrings(buf, offset, parentPathv);
552
assert(offset == bufsize);
553
554
magic = magicNumber();
555
556
/* write the two structs and the data buffer */
557
write(c->childenv[1], (char *)&magic, sizeof(magic)); // magic number first
558
write(c->childenv[1], (char *)c, sizeof(*c));
559
write(c->childenv[1], (char *)&sp, sizeof(sp));
560
write(c->childenv[1], buf, bufsize);
561
free(buf);
562
563
/* In this mode an external main() in invoked which calls back into
564
* childProcess() in this file, rather than directly
565
* via the statement below */
566
return resultPid;
567
}
568
569
/*
570
* Start a child process running function childProcess.
571
* This function only returns in the parent.
572
*/
573
static pid_t
574
startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {
575
switch (c->mode) {
576
/* vfork(2) is deprecated on Solaris */
577
case MODE_VFORK:
578
return vforkChild(c);
579
case MODE_FORK:
580
return forkChild(c);
581
case MODE_POSIX_SPAWN:
582
return spawnChild(env, process, c, helperpath);
583
default:
584
return -1;
585
}
586
}
587
588
JNIEXPORT jint JNICALL
589
Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env,
590
jobject process,
591
jint mode,
592
jbyteArray helperpath,
593
jbyteArray prog,
594
jbyteArray argBlock, jint argc,
595
jbyteArray envBlock, jint envc,
596
jbyteArray dir,
597
jintArray std_fds,
598
jboolean redirectErrorStream)
599
{
600
int errnum;
601
int resultPid = -1;
602
int in[2], out[2], err[2], fail[2], childenv[2];
603
jint *fds = NULL;
604
const char *phelperpath = NULL;
605
const char *pprog = NULL;
606
const char *pargBlock = NULL;
607
const char *penvBlock = NULL;
608
ChildStuff *c;
609
610
in[0] = in[1] = out[0] = out[1] = err[0] = err[1] = fail[0] = fail[1] = -1;
611
childenv[0] = childenv[1] = -1;
612
613
if ((c = NEW(ChildStuff, 1)) == NULL) return -1;
614
c->argv = NULL;
615
c->envv = NULL;
616
c->pdir = NULL;
617
618
/* Convert prog + argBlock into a char ** argv.
619
* Add one word room for expansion of argv for use by
620
* execve_as_traditional_shell_script.
621
* This word is also used when using posix_spawn mode
622
*/
623
assert(prog != NULL && argBlock != NULL);
624
if ((phelperpath = getBytes(env, helperpath)) == NULL) goto Catch;
625
if ((pprog = getBytes(env, prog)) == NULL) goto Catch;
626
if ((pargBlock = getBytes(env, argBlock)) == NULL) goto Catch;
627
if ((c->argv = NEW(const char *, argc + 3)) == NULL) goto Catch;
628
c->argv[0] = pprog;
629
c->argc = argc + 2;
630
initVectorFromBlock(c->argv+1, pargBlock, argc);
631
632
if (envBlock != NULL) {
633
/* Convert envBlock into a char ** envv */
634
if ((penvBlock = getBytes(env, envBlock)) == NULL) goto Catch;
635
if ((c->envv = NEW(const char *, envc + 1)) == NULL) goto Catch;
636
initVectorFromBlock(c->envv, penvBlock, envc);
637
}
638
639
if (dir != NULL) {
640
if ((c->pdir = getBytes(env, dir)) == NULL) goto Catch;
641
}
642
643
assert(std_fds != NULL);
644
fds = (*env)->GetIntArrayElements(env, std_fds, NULL);
645
if (fds == NULL) goto Catch;
646
647
if ((fds[0] == -1 && pipe(in) < 0) ||
648
(fds[1] == -1 && pipe(out) < 0) ||
649
(fds[2] == -1 && pipe(err) < 0) ||
650
(pipe(childenv) < 0) ||
651
(pipe(fail) < 0)) {
652
throwIOException(env, errno, "Bad file descriptor");
653
goto Catch;
654
}
655
c->fds[0] = fds[0];
656
c->fds[1] = fds[1];
657
c->fds[2] = fds[2];
658
659
copyPipe(in, c->in);
660
copyPipe(out, c->out);
661
copyPipe(err, c->err);
662
copyPipe(fail, c->fail);
663
copyPipe(childenv, c->childenv);
664
665
c->redirectErrorStream = redirectErrorStream;
666
c->mode = mode;
667
668
/* In posix_spawn mode, require the child process to signal aliveness
669
* right after it comes up. This is because there are implementations of
670
* posix_spawn() which do not report failed exec()s back to the caller
671
* (e.g. glibc, see JDK-8223777). In those cases, the fork() will have
672
* worked and successfully started the child process, but the exec() will
673
* have failed. There is no way for us to distinguish this from a target
674
* binary just exiting right after start.
675
*
676
* Note that we could do this additional handshake in all modes but for
677
* prudence only do it when it is needed (in posix_spawn mode). */
678
c->sendAlivePing = (mode == MODE_POSIX_SPAWN) ? 1 : 0;
679
680
resultPid = startChild(env, process, c, phelperpath);
681
assert(resultPid != 0);
682
683
if (resultPid < 0) {
684
switch (c->mode) {
685
case MODE_VFORK:
686
throwIOException(env, errno, "vfork failed");
687
break;
688
case MODE_FORK:
689
throwIOException(env, errno, "fork failed");
690
break;
691
case MODE_POSIX_SPAWN:
692
throwIOException(env, errno, "posix_spawn failed");
693
break;
694
}
695
goto Catch;
696
}
697
close(fail[1]); fail[1] = -1; /* See: WhyCantJohnnyExec (childproc.c) */
698
699
/* If we expect the child to ping aliveness, wait for it. */
700
if (c->sendAlivePing) {
701
switch(readFully(fail[0], &errnum, sizeof(errnum))) {
702
case 0: /* First exec failed; */
703
{
704
int tmpStatus = 0;
705
int p = waitpid(resultPid, &tmpStatus, 0);
706
throwExitCause(env, p, tmpStatus);
707
goto Catch;
708
}
709
case sizeof(errnum):
710
assert(errnum == CHILD_IS_ALIVE);
711
if (errnum != CHILD_IS_ALIVE) {
712
/* Should never happen since the first thing the spawn
713
* helper should do is to send an alive ping to the parent,
714
* before doing any subsequent work. */
715
throwIOException(env, 0, "Bad code from spawn helper "
716
"(Failed to exec spawn helper)");
717
goto Catch;
718
}
719
break;
720
default:
721
throwIOException(env, errno, "Read failed");
722
goto Catch;
723
}
724
}
725
726
switch (readFully(fail[0], &errnum, sizeof(errnum))) {
727
case 0: break; /* Exec succeeded */
728
case sizeof(errnum):
729
waitpid(resultPid, NULL, 0);
730
throwIOException(env, errnum, "Exec failed");
731
goto Catch;
732
default:
733
throwIOException(env, errno, "Read failed");
734
goto Catch;
735
}
736
737
fds[0] = (in [1] != -1) ? in [1] : -1;
738
fds[1] = (out[0] != -1) ? out[0] : -1;
739
fds[2] = (err[0] != -1) ? err[0] : -1;
740
741
Finally:
742
/* Always clean up the child's side of the pipes */
743
closeSafely(in [0]);
744
closeSafely(out[1]);
745
closeSafely(err[1]);
746
747
/* Always clean up fail and childEnv descriptors */
748
closeSafely(fail[0]);
749
closeSafely(fail[1]);
750
closeSafely(childenv[0]);
751
closeSafely(childenv[1]);
752
753
releaseBytes(env, helperpath, phelperpath);
754
releaseBytes(env, prog, pprog);
755
releaseBytes(env, argBlock, pargBlock);
756
releaseBytes(env, envBlock, penvBlock);
757
releaseBytes(env, dir, c->pdir);
758
759
free(c->argv);
760
free(c->envv);
761
free(c);
762
763
if (fds != NULL)
764
(*env)->ReleaseIntArrayElements(env, std_fds, fds, 0);
765
766
return resultPid;
767
768
Catch:
769
/* Clean up the parent's side of the pipes in case of failure only */
770
closeSafely(in [1]); in[1] = -1;
771
closeSafely(out[0]); out[0] = -1;
772
closeSafely(err[0]); err[0] = -1;
773
goto Finally;
774
}
775
776
777