1 /*
2  * Copyright (c) 1997, 2013, 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 #include <assert.h>
27 #include "java_lang_ProcessImpl.h"
28 
29 #include "jni.h"
30 #include "jvm.h"
31 #include "jni_util.h"
32 #include "io_util.h"
33 #include <windows.h>
34 #include <io.h>
35 
36 /* We try to make sure that we can read and write 4095 bytes (the
37  * fixed limit on Linux) to the pipe on all operating systems without
38  * deadlock.  Windows 2000 inexplicably appears to need an extra 24
39  * bytes of slop to avoid deadlock.
40  */
41 #define PIPE_SIZE (4096+24)
42 
43 /* We have THREE locales in action:
44  * 1. Thread default locale - dictates UNICODE-to-8bit conversion
45  * 2. System locale that defines the message localization
46  * 3. The file name locale
47  * Each locale could be an extended locale, that means that text cannot be
48  * mapped to 8bit sequence without multibyte encoding.
49  * VM is ready for that, if text is UTF-8.
50  * Here we make the work right from the beginning.
51  */
os_error_message(int errnum,WCHAR * utf16_OSErrorMsg,size_t maxMsgLength)52 size_t os_error_message(int errnum, WCHAR* utf16_OSErrorMsg, size_t maxMsgLength) {
53     size_t n = (size_t)FormatMessageW(
54             FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
55             NULL,
56             (DWORD)errnum,
57             0,
58             utf16_OSErrorMsg,
59             (DWORD)maxMsgLength,
60             NULL);
61     if (n > 3) {
62         // Drop final '.', CR, LF
63         if (utf16_OSErrorMsg[n - 1] == L'\n') --n;
64         if (utf16_OSErrorMsg[n - 1] == L'\r') --n;
65         if (utf16_OSErrorMsg[n - 1] == L'.') --n;
66         utf16_OSErrorMsg[n] = L'\0';
67     }
68     return n;
69 }
70 
71 #define MESSAGE_LENGTH (256 + 100)
72 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
73 
74 static void
win32Error(JNIEnv * env,const WCHAR * functionName)75 win32Error(JNIEnv *env, const WCHAR *functionName)
76 {
77     WCHAR utf16_OSErrorMsg[MESSAGE_LENGTH - 100];
78     WCHAR utf16_javaMessage[MESSAGE_LENGTH];
79     /*Good suggestion about 2-bytes-per-symbol in localized error reports*/
80     char  utf8_javaMessage[MESSAGE_LENGTH*2];
81     const int errnum = (int)GetLastError();
82     int n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg));
83     n = (n > 0)
84         ? swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s error=%d, %s", functionName, errnum, utf16_OSErrorMsg)
85         : swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s failed, error=%d", functionName, errnum);
86 
87     if (n > 0) /*terminate '\0' is not a part of conversion procedure*/
88         n = WideCharToMultiByte(
89             CP_UTF8,
90             0,
91             utf16_javaMessage,
92             n, /*by creation n <= MESSAGE_LENGTH*/
93             utf8_javaMessage,
94             MESSAGE_LENGTH*2,
95             NULL,
96             NULL);
97 
98     /*no way to die*/
99     {
100         const char *errorMessage = "Secondary error while OS message extraction";
101         if (n > 0) {
102             utf8_javaMessage[min(MESSAGE_LENGTH*2 - 1, n)] = '\0';
103             errorMessage = utf8_javaMessage;
104         }
105         JNU_ThrowIOException(env, errorMessage);
106     }
107 }
108 
109 static void
closeSafely(HANDLE handle)110 closeSafely(HANDLE handle)
111 {
112     if (handle != INVALID_HANDLE_VALUE)
113         CloseHandle(handle);
114 }
115 
hasInheritFlag(HANDLE handle)116 static BOOL hasInheritFlag(HANDLE handle)
117 {
118     DWORD mask;
119     if (GetHandleInformation(handle, &mask)) {
120         return mask & HANDLE_FLAG_INHERIT;
121     }
122     return FALSE;
123 }
124 
125 #define HANDLE_STORAGE_SIZE 6
126 #define OFFSET_READ  0
127 #define OFFSET_WRITE 1
128 //long signed version of INVALID_HANDLE_VALUE
129 #define JAVA_INVALID_HANDLE_VALUE ((jlong) -1)
130 #define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ)
131 
132 /* Pipe holder structure */
133 typedef struct _STDHOLDER {
134     HANDLE  pipe[2];
135     int     offset;
136 } STDHOLDER;
137 
138 /* Responsible for correct initialization of the [pHolder] structure
139    (that is used for handles recycling) if needs,
140    and appropriate setup of IOE handle [phStd] for child process based
141    on created pipe or Java handle. */
initHolder(JNIEnv * env,jlong * pjhandles,STDHOLDER * pHolder,HANDLE * phStd)142 static BOOL initHolder(
143     JNIEnv *env,
144     jlong *pjhandles,   /* IN OUT - the handle form Java,
145                                     that can be a file, console or undefined */
146     STDHOLDER *pHolder, /* OUT    - initialized structure that holds pipe
147                                     handles */
148     HANDLE *phStd       /* OUT    - initialized handle for child process */
149 ) {
150     /* Here we test the value from Java against invalid
151        handle value. We are not using INVALID_HANDLE_VALUE macro
152        due to double signed/unsigned and 32/64bit ambiguity.
153        Otherwise it will be easy to get the wrong
154        value   0x00000000FFFFFFFF
155        instead 0xFFFFFFFFFFFFFFFF. */
156     if (*pjhandles != JAVA_INVALID_HANDLE_VALUE) {
157         /* Java file or console redirection */
158         *phStd = (HANDLE) *pjhandles;
159         /* Here we set the related Java stream (Process.getXXXXStream())
160            to [ProcessBuilder.NullXXXXStream.INSTANCE] value.
161            The initial Java handle [*pjhandles] will be closed in
162            ANY case. It is not a handle leak. */
163         *pjhandles = JAVA_INVALID_HANDLE_VALUE;
164     } else {
165         /* Creation of parent-child pipe */
166         if (!CreatePipe(
167             &pHolder->pipe[OFFSET_READ],
168             &pHolder->pipe[OFFSET_WRITE],
169             NULL, /* we would like to inherit
170                      default process access,
171                      instead of 'Everybody' access */
172             PIPE_SIZE))
173         {
174             win32Error(env, L"CreatePipe");
175             return FALSE;
176         } else {
177             /* [thisProcessEnd] has no the inherit flag because
178                the [lpPipeAttributes] param of [CreatePipe]
179                had the NULL value. */
180             HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)];
181             *phStd = pHolder->pipe[pHolder->offset];
182             *pjhandles = (jlong) thisProcessEnd;
183         }
184     }
185     /* Pipe handle will be closed in the [releaseHolder] call,
186        file handle will be closed in Java.
187        The long-live handle need to restore the inherit flag,
188        we do it later in the [prepareIOEHandleState] call. */
189     SetHandleInformation(
190         *phStd,
191         HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
192     return TRUE;
193 }
194 
195 /* Smart recycling of pipe handles in [pHolder]. For the failed
196    create process attempts, both ends of pipe need to be released.
197    The [complete] has the [TRUE] value in the failed attempt. */
releaseHolder(BOOL complete,STDHOLDER * pHolder)198 static void releaseHolder(BOOL complete, STDHOLDER *pHolder) {
199     closeSafely(pHolder->pipe[pHolder->offset]);
200     if (complete) {
201         /* Error occur, close this process pipe end */
202         closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]);
203     }
204 }
205 
206 /* Stores and drops the inherit flag of handles that should not
207    be shared with the child process by default, but can hold the
208    inherit flag due to MS process birth specific. */
prepareIOEHandleState(HANDLE * stdIOE,BOOL * inherit)209 static void prepareIOEHandleState(
210     HANDLE *stdIOE,
211     BOOL *inherit)
212 {
213     int i;
214     for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) {
215         HANDLE hstd = stdIOE[i];
216         if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) {
217             /* FALSE by default */
218             inherit[i] = TRUE;
219             /* Java does not need implicit inheritance for IOE handles,
220                so we drop inherit flag that probably was installed by
221                previous CreateProcess call that launched current process.
222                We will return the handle state back after CreateProcess call.
223                By clearing inherit flag we prevent "greedy grandchild" birth.
224                The explicit inheritance for child process IOE handles is
225                implemented in the [initHolder] call. */
226             SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0);
227         }
228     }
229 }
230 
231 /* Restores the inheritance flag of handles from stored values. */
restoreIOEHandleState(const HANDLE * stdIOE,const BOOL * inherit)232 static void restoreIOEHandleState(
233     const HANDLE *stdIOE,
234     const BOOL *inherit)
235 {
236     /* The set of current process standard IOE handles and
237        the set of child process IOE handles can intersect.
238        To restore the inherit flag right, we use backward
239        array iteration. */
240     int i;
241     for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i)
242         if (INVALID_HANDLE_VALUE != stdIOE[i]) {
243            /* Restore inherit flag for any case.
244               The handle can be changed by explicit inheritance.*/
245             SetHandleInformation(stdIOE[i],
246                 HANDLE_FLAG_INHERIT,
247                 inherit[i] ? HANDLE_FLAG_INHERIT : 0);
248         }
249 }
250 
251 /* Please, read about the MS inheritance problem
252    http://support.microsoft.com/kb/315939
253    and critical section/synchronized block solution. */
processCreate(JNIEnv * env,const jchar * pcmd,const jchar * penvBlock,const jchar * pdir,jlong * handles,jboolean redirectErrorStream)254 static jlong processCreate(
255     JNIEnv *env,
256     const jchar *pcmd,
257     const jchar *penvBlock,
258     const jchar *pdir,
259     jlong *handles,
260     jboolean redirectErrorStream)
261 {
262     jlong ret = 0L;
263     STARTUPINFOW si = {sizeof(si)};
264 
265     /* Handles for which the inheritance flag must be restored. */
266     HANDLE stdIOE[HANDLE_STORAGE_SIZE] = {
267         /* Current process standard IOE handles: JDK-7147084 */
268         INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
269         /* Child process IOE handles: JDK-6921885 */
270         (HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]};
271     BOOL inherit[HANDLE_STORAGE_SIZE] = {
272         FALSE, FALSE, FALSE,
273         FALSE, FALSE, FALSE};
274 
275     /* These three should not be closed by CloseHandle! */
276     stdIOE[0] = GetStdHandle(STD_INPUT_HANDLE);
277     stdIOE[1] = GetStdHandle(STD_OUTPUT_HANDLE);
278     stdIOE[2] = GetStdHandle(STD_ERROR_HANDLE);
279 
280     prepareIOEHandleState(stdIOE, inherit);
281     {
282         /* Input */
283         STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ};
284         if (initHolder(env, &handles[0], &holderIn, &si.hStdInput)) {
285 
286             /* Output */
287             STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
288             if (initHolder(env, &handles[1], &holderOut, &si.hStdOutput)) {
289 
290                 /* Error */
291                 STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
292                 BOOL success;
293                 if (redirectErrorStream) {
294                     si.hStdError = si.hStdOutput;
295                     /* Here we set the error stream to [ProcessBuilder.NullInputStream.INSTANCE]
296                        value. That is in accordance with Java Doc for the redirection case.
297                        The Java file for the [ handles[2] ] will be closed in ANY case. It is not
298                        a handle leak. */
299                     handles[2] = JAVA_INVALID_HANDLE_VALUE;
300                     success = TRUE;
301                 } else {
302                     success = initHolder(env, &handles[2], &holderErr, &si.hStdError);
303                 }
304 
305                 if (success) {
306                     PROCESS_INFORMATION pi;
307                     DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
308 
309                     /* If the standard I/O is inherited, CREATE_NO_WINDOW must not be used. */
310                     if (GetConsoleWindow() != NULL &&
311                         (si.hStdInput  == stdIOE[0] ||
312                          si.hStdOutput == stdIOE[1] ||
313                          si.hStdError  == (redirectErrorStream ? stdIOE[1] : stdIOE[2])))
314                     {
315                         processFlag &= ~CREATE_NO_WINDOW;
316                     }
317 
318                     si.dwFlags = STARTF_USESTDHANDLES;
319                     if (!CreateProcessW(
320                         NULL,             /* executable name */
321                         (LPWSTR)pcmd,     /* command line */
322                         NULL,             /* process security attribute */
323                         NULL,             /* thread security attribute */
324                         TRUE,             /* inherits system handles */
325                         processFlag,      /* selected based on exe type */
326                         (LPVOID)penvBlock,/* environment block */
327                         (LPCWSTR)pdir,    /* change to the new current directory */
328                         &si,              /* (in)  startup information */
329                         &pi))             /* (out) process information */
330                     {
331                         win32Error(env, L"CreateProcess");
332                     } else {
333                         closeSafely(pi.hThread);
334                         ret = (jlong)pi.hProcess;
335                     }
336                 }
337                 releaseHolder(ret == 0, &holderErr);
338                 releaseHolder(ret == 0, &holderOut);
339             }
340             releaseHolder(ret == 0, &holderIn);
341         }
342     }
343     restoreIOEHandleState(stdIOE, inherit);
344 
345     return ret;
346 }
347 
348 JNIEXPORT jlong JNICALL
Java_java_lang_ProcessImpl_create(JNIEnv * env,jclass ignored,jstring cmd,jstring envBlock,jstring dir,jlongArray stdHandles,jboolean redirectErrorStream)349 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
350                                   jstring cmd,
351                                   jstring envBlock,
352                                   jstring dir,
353                                   jlongArray stdHandles,
354                                   jboolean redirectErrorStream)
355 {
356     jlong ret = 0;
357     if (cmd != NULL && stdHandles != NULL) {
358         const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL);
359         if (pcmd != NULL) {
360             const jchar *penvBlock = (envBlock != NULL)
361                 ? (*env)->GetStringChars(env, envBlock, NULL)
362                 : NULL;
363             if (!(*env)->ExceptionCheck(env)) {
364                 const jchar *pdir = (dir != NULL)
365                     ? (*env)->GetStringChars(env, dir, NULL)
366                     : NULL;
367                 if (!(*env)->ExceptionCheck(env)) {
368                     jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
369                     if (handles != NULL) {
370                         ret = processCreate(
371                             env,
372                             pcmd,
373                             penvBlock,
374                             pdir,
375                             handles,
376                             redirectErrorStream);
377                         (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
378                     }
379                     if (pdir != NULL)
380                         (*env)->ReleaseStringChars(env, dir, pdir);
381                 }
382                 if (penvBlock != NULL)
383                     (*env)->ReleaseStringChars(env, envBlock, penvBlock);
384             }
385             (*env)->ReleaseStringChars(env, cmd, pcmd);
386         }
387     }
388     return ret;
389 }
390 
391 JNIEXPORT jint JNICALL
Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv * env,jclass ignored,jlong handle)392 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
393 {
394     DWORD exit_code;
395     if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
396         win32Error(env, L"GetExitCodeProcess");
397     return exit_code;
398 }
399 
400 JNIEXPORT jint JNICALL
Java_java_lang_ProcessImpl_getStillActive(JNIEnv * env,jclass ignored)401 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
402 {
403     return STILL_ACTIVE;
404 }
405 
406 JNIEXPORT void JNICALL
Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv * env,jclass ignored,jlong handle)407 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
408 {
409     HANDLE events[2];
410     events[0] = (HANDLE) handle;
411     events[1] = JVM_GetThreadInterruptEvent();
412 
413     if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
414                                FALSE,    /* Wait for ANY event */
415                                INFINITE)  /* Wait forever */
416         == WAIT_FAILED)
417         win32Error(env, L"WaitForMultipleObjects");
418 }
419 
420 JNIEXPORT void JNICALL
Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv * env,jclass ignored,jlong handle,jlong timeoutMillis)421 Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env,
422                                                        jclass ignored,
423                                                        jlong handle,
424                                                        jlong timeoutMillis)
425 {
426     HANDLE events[2];
427     DWORD dwTimeout = (DWORD)timeoutMillis;
428     DWORD result;
429     events[0] = (HANDLE) handle;
430     events[1] = JVM_GetThreadInterruptEvent();
431     result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
432                                     FALSE,    /* Wait for ANY event */
433                                     dwTimeout);  /* Wait for dwTimeout */
434 
435     if (result == WAIT_FAILED)
436         win32Error(env, L"WaitForMultipleObjects");
437 }
438 
439 JNIEXPORT void JNICALL
Java_java_lang_ProcessImpl_terminateProcess(JNIEnv * env,jclass ignored,jlong handle)440 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
441 {
442     TerminateProcess((HANDLE) handle, 1);
443 }
444 
445 JNIEXPORT jboolean JNICALL
Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv * env,jclass ignored,jlong handle)446 Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle)
447 {
448     DWORD dwExitStatus;
449     GetExitCodeProcess((HANDLE) handle, &dwExitStatus);
450     return dwExitStatus == STILL_ACTIVE;
451 }
452 
453 JNIEXPORT jboolean JNICALL
Java_java_lang_ProcessImpl_closeHandle(JNIEnv * env,jclass ignored,jlong handle)454 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
455 {
456     return (jboolean) CloseHandle((HANDLE) handle);
457 }
458 
459 /**
460  * Returns a copy of the Unicode characters of a string. Fow now this
461  * function doesn't handle long path names and other issues.
462  */
getPath(JNIEnv * env,jstring ps)463 static WCHAR* getPath(JNIEnv *env, jstring ps) {
464     WCHAR *pathbuf = NULL;
465     const jchar *chars = (*(env))->GetStringChars(env, ps, NULL);
466     if (chars != NULL) {
467         size_t pathlen = wcslen(chars);
468         pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR));
469         if (pathbuf == NULL) {
470             JNU_ThrowOutOfMemoryError(env, NULL);
471         } else {
472             wcscpy(pathbuf, chars);
473         }
474         (*env)->ReleaseStringChars(env, ps, chars);
475     }
476     return pathbuf;
477 }
478 
479 JNIEXPORT jlong JNICALL
Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv * env,jclass ignored,jstring path)480 Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path)
481 {
482     const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA);
483     const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
484     const DWORD disposition = OPEN_ALWAYS;
485     const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
486     HANDLE h;
487     WCHAR *pathbuf = getPath(env, path);
488     if (pathbuf == NULL) {
489         /* Exception already pending */
490         return -1;
491     }
492     h = CreateFileW(
493         pathbuf,            /* Wide char path name */
494         access,             /* Read and/or write permission */
495         sharing,            /* File sharing flags */
496         NULL,               /* Security attributes */
497         disposition,        /* creation disposition */
498         flagsAndAttributes, /* flags and attributes */
499         NULL);
500     free(pathbuf);
501     if (h == INVALID_HANDLE_VALUE) {
502         JNU_ThrowIOExceptionWithLastError(env, "CreateFileW");
503     }
504     return ptr_to_jlong(h);
505 }
506