src/windows/native/java/lang/ProcessImpl_md.c

Print this page


   1 /*
   2  * Copyright (c) 1997, 2010, 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


 118     static const char * const format = "%s error=%d, %s";
 119     static const char * const fallbackFormat = "%s failed, error=%d";
 120     char buf[256];
 121     char errmsg[sizeof(buf) + 100];
 122     const int errnum = GetLastError();
 123     const int n = JVM_GetLastErrorString(buf, sizeof(buf));
 124     if (n > 0)
 125         sprintf(errmsg, format, functionName, errnum, buf);
 126     else
 127         sprintf(errmsg, fallbackFormat, functionName, errnum);
 128     JNU_ThrowIOException(env, errmsg);
 129 }
 130 
 131 static void
 132 closeSafely(HANDLE handle)
 133 {
 134     if (handle != INVALID_HANDLE_VALUE)
 135         CloseHandle(handle);
 136 }
 137 
 138 JNIEXPORT jlong JNICALL
 139 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
 140                                   jstring cmd,
 141                                   jstring envBlock,
 142                                   jstring dir,
 143                                   jlongArray stdHandles,
 144                                   jboolean redirectErrorStream)
 145 {
 146     HANDLE inRead   = INVALID_HANDLE_VALUE;
 147     HANDLE inWrite  = INVALID_HANDLE_VALUE;
 148     HANDLE outRead  = INVALID_HANDLE_VALUE;
 149     HANDLE outWrite = INVALID_HANDLE_VALUE;
 150     HANDLE errRead  = INVALID_HANDLE_VALUE;
 151     HANDLE errWrite = INVALID_HANDLE_VALUE;
 152     SECURITY_ATTRIBUTES sa;
 153     PROCESS_INFORMATION pi;
 154     STARTUPINFOW si;
 155     const jchar*  pcmd = NULL;
 156     const jchar*  pdir = NULL;
 157     const jchar*  penvBlock = NULL;
 158     jlong  *handles = NULL;
 159     jlong ret = 0;
 160     OSVERSIONINFO ver;
 161     jboolean onNT = JNI_FALSE;
 162     DWORD processFlag;
 163 
 164     ver.dwOSVersionInfoSize = sizeof(ver);
 165     GetVersionEx(&ver);
 166     if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT)
 167         onNT = JNI_TRUE;
 168 
 169     assert(cmd != NULL);
 170     pcmd = (*env)->GetStringChars(env, cmd, NULL);
 171     if (pcmd == NULL) goto Catch;
 172 
 173     if (dir != 0) {
 174         pdir = (*env)->GetStringChars(env, dir, NULL);
 175         if (pdir == NULL) goto Catch;
 176     }
 177     if (envBlock != NULL) {
 178         penvBlock = ((*env)->GetStringChars(env, envBlock, NULL));
 179         if (penvBlock == NULL) goto Catch;
 180     }
 181     assert(stdHandles != NULL);
 182     handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
 183     if (handles == NULL) goto Catch;
 184 
 185     memset(&si, 0, sizeof(si));
 186     si.cb = sizeof(si);
 187     si.dwFlags = STARTF_USESTDHANDLES;



 188 
 189     sa.nLength = sizeof(sa);
 190     sa.lpSecurityDescriptor = 0;
 191     sa.bInheritHandle = TRUE;


 192 
 193     if (handles[0] != (jlong) -1) {
 194         si.hStdInput = (HANDLE) handles[0];
 195         handles[0] = (jlong) -1;























 196     } else {
 197         if (! CreatePipe(&inRead,  &inWrite,  &sa, PIPE_SIZE)) {








 198             win32Error(env, "CreatePipe");
 199             goto Catch;







 200         }
 201         si.hStdInput = inRead;
 202         SetHandleInformation(inWrite, HANDLE_FLAG_INHERIT, 0);
 203         handles[0] = (jlong) inWrite;
 204     }
 205     SetHandleInformation(si.hStdInput,
 206         HANDLE_FLAG_INHERIT,
 207         HANDLE_FLAG_INHERIT);






 208 
 209     if (handles[1] != (jlong) -1) {
 210         si.hStdOutput = (HANDLE) handles[1];
 211         handles[1] = (jlong) -1;
 212     } else {
 213         if (! CreatePipe(&outRead, &outWrite, &sa, PIPE_SIZE)) {
 214             win32Error(env, "CreatePipe");
 215             goto Catch;

 216         }
 217         si.hStdOutput = outWrite;
 218         SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, 0);
 219         handles[1] = (jlong) outRead;




















 220     }
 221     SetHandleInformation(si.hStdOutput,

















 222         HANDLE_FLAG_INHERIT,
 223         HANDLE_FLAG_INHERIT);


 224 














































 225     if (redirectErrorStream) {
 226         si.hStdError = si.hStdOutput;
 227         handles[2] = (jlong) -1;
 228     } else if (handles[2] != (jlong) -1) {
 229         si.hStdError = (HANDLE) handles[2];
 230         handles[2] = (jlong) -1;


 231     } else {
 232         if (! CreatePipe(&errRead, &errWrite, &sa, PIPE_SIZE)) {
 233             win32Error(env, "CreatePipe");
 234             goto Catch;
 235         }
 236         si.hStdError = errWrite;
 237         SetHandleInformation(errRead, HANDLE_FLAG_INHERIT, 0);
 238         handles[2] = (jlong) errRead;
 239     }
 240     SetHandleInformation(si.hStdError,
 241         HANDLE_FLAG_INHERIT,
 242         HANDLE_FLAG_INHERIT);
 243 
 244     if (onNT)
 245         processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
 246     else
 247         processFlag = selectProcessFlag(env, cmd) | CREATE_UNICODE_ENVIRONMENT;
 248     ret = CreateProcessW(0,                /* executable name */


 249                          (LPWSTR)pcmd,     /* command line */
 250                          0,                /* process security attribute */
 251                          0,                /* thread security attribute */
 252                          TRUE,             /* inherits system handles */
 253                          processFlag,      /* selected based on exe type */
 254                          (LPVOID)penvBlock,/* environment block */
 255                          (LPCWSTR)pdir,    /* change to the new current directory */
 256                          &si,              /* (in)  startup information */
 257                          &pi);             /* (out) process information */
 258     if (!ret) {
 259         win32Error(env, "CreateProcess");
 260         goto Catch;


 261     }








 262 
 263     CloseHandle(pi.hThread);
 264     ret = (jlong)pi.hProcess;
 265 
 266  Finally:
 267     /* Always clean up the child's side of the pipes */
 268     closeSafely(inRead);
 269     closeSafely(outWrite);
 270     closeSafely(errWrite);
 271 
 272     if (pcmd != NULL)
 273         (*env)->ReleaseStringChars(env, cmd, pcmd);





















 274     if (pdir != NULL)
 275         (*env)->ReleaseStringChars(env, dir, pdir);
 276     if (penvBlock != NULL)
 277         (*env)->ReleaseStringChars(env, envBlock, penvBlock);
 278     if (handles != NULL)
 279         (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);

 280     return ret;
 281 
 282  Catch:
 283     /* Clean up the parent's side of the pipes in case of failure only */
 284     closeSafely(inWrite);
 285     closeSafely(outRead);
 286     closeSafely(errRead);
 287     goto Finally;
 288 }
 289 
 290 JNIEXPORT jint JNICALL
 291 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
 292 {
 293     DWORD exit_code;
 294     if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
 295         win32Error(env, "GetExitCodeProcess");
 296     return exit_code;
 297 }
 298 
 299 JNIEXPORT jint JNICALL
 300 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
 301 {
 302     return STILL_ACTIVE;
 303 }
 304 
 305 JNIEXPORT void JNICALL
 306 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
 307 {


   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


 118     static const char * const format = "%s error=%d, %s";
 119     static const char * const fallbackFormat = "%s failed, error=%d";
 120     char buf[256];
 121     char errmsg[sizeof(buf) + 100];
 122     const int errnum = GetLastError();
 123     const int n = JVM_GetLastErrorString(buf, sizeof(buf));
 124     if (n > 0)
 125         sprintf(errmsg, format, functionName, errnum, buf);
 126     else
 127         sprintf(errmsg, fallbackFormat, functionName, errnum);
 128     JNU_ThrowIOException(env, errmsg);
 129 }
 130 
 131 static void
 132 closeSafely(HANDLE handle)
 133 {
 134     if (handle != INVALID_HANDLE_VALUE)
 135         CloseHandle(handle);
 136 }
 137 
 138 static BOOL hasInheritFlag(HANDLE handle)






 139 {
 140     DWORD mask;
 141     if (GetHandleInformation(handle, &mask)) {
 142         return mask & HANDLE_FLAG_INHERIT;



























 143     }
 144     return FALSE;
 145 }





 146 
 147 #define HANDLE_STORAGE_SIZE 6
 148 #define OFFSET_READ  0
 149 #define OFFSET_WRITE 1
 150 //long signed version of INVALID_HANDLE_VALUE
 151 #define JAVA_INVALID_HANDLE_VALUE ((jlong) -1)
 152 #define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ)
 153 
 154 /* Pipe holder structure */
 155 typedef struct _STDHOLDER {
 156     HANDLE  pipe[2];
 157     int     offset;
 158 } STDHOLDER;
 159 
 160 /* Responsible for correct initialization of the [pHolder] structure
 161    (that is used for handles recycling) if needs,
 162    and appropriate setup of IOE handle [phStd] for child process based
 163    on created pipe or Java handle. */
 164 static BOOL initHolder(
 165     JNIEnv *env,
 166     jlong *pjhandles,   /* IN OUT - the handle form Java,
 167                                     that can be a file, console or undefined */
 168     STDHOLDER *pHolder, /* OUT    - initialized structure that holds pipe
 169                                     handles */
 170     HANDLE *phStd       /* OUT    - initialized handle for child process */
 171 ) {
 172     /* Here we test the value from Java against invalid
 173        handle value. We are not using INVALID_HANDLE_VALUE macro
 174        due to double signed/unsigned and 32/64bit ambiguity.
 175        Otherwise it will be easy to get the wrong
 176        value   0x00000000FFFFFFFF
 177        instead 0xFFFFFFFFFFFFFFFF. */
 178     if (*pjhandles != JAVA_INVALID_HANDLE_VALUE) {
 179         /* Java file or console redirection */
 180         *phStd = (HANDLE) *pjhandles;
 181         /* Here we set the related Java stream (Process.getXXXXStream())
 182            to [ProcessBuilder.NullXXXXStream.INSTANCE] value.
 183            The initial Java handle [*pjhandles] will be closed in
 184            ANY case. It is not a handle leak. */
 185         *pjhandles = JAVA_INVALID_HANDLE_VALUE;
 186     } else {
 187         /* Creation of parent-child pipe */
 188         if (!CreatePipe(
 189             &pHolder->pipe[OFFSET_READ],
 190             &pHolder->pipe[OFFSET_WRITE],
 191             NULL, /* we would like to inherit
 192                      default process access,
 193                      instead of 'Everybody' access */
 194             PIPE_SIZE))
 195         {
 196             win32Error(env, "CreatePipe");
 197             return FALSE;
 198         } else {
 199             /* [thisProcessEnd] has no the inherit flag because
 200                the [lpPipeAttributes] param of [CreatePipe]
 201                had the NULL value. */
 202             HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)];
 203             *phStd = pHolder->pipe[pHolder->offset];
 204             *pjhandles = (jlong) thisProcessEnd;
 205         }



 206     }
 207     /* Pipe handle will be closed in the [releaseHolder] call,
 208        file handle will be closed in Java.
 209        The long-live handle need to restore the inherit flag,
 210        we do it later in the [prepareIOEHandleState] call. */
 211     SetHandleInformation(
 212         *phStd,
 213         HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
 214     return TRUE;
 215 }
 216 
 217 /* Smart recycling of pipe handles in [pHolder]. For the failed
 218    create process attempts, both ends of pipe need to be released.
 219    The [complete] has the [TRUE] value in the failed attempt. */
 220 static void releaseHolder(BOOL complete, STDHOLDER *pHolder) {
 221     closeSafely(pHolder->pipe[pHolder->offset]);
 222     if (complete) {
 223         /* Error occur, close this process pipe end */
 224         closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]);
 225     }
 226 }
 227 
 228 /* Stores and drops the inherit flag of handles that should not
 229    be shared with the child process by default, but can hold the
 230    inherit flag due to MS process birth specific. */
 231 static void prepareIOEHandleState(
 232     HANDLE *stdIOE,
 233     BOOL *inherit)
 234 {
 235     int i;
 236     for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) {
 237         HANDLE hstd = stdIOE[i];
 238         if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) {
 239             /* FALSE by default */
 240             inherit[i] = TRUE;
 241             /* Java does not need implicit inheritance for IOE handles,
 242                so we drop inherit flag that probably was installed by
 243                previous CreateProcess call that launched current process.
 244                We will return the handle state back after CreateProcess call.
 245                By clearing inherit flag we prevent "greedy grandchild" birth.
 246                The explicit inheritance for child process IOE handles is
 247                implemented in the [initHolder] call. */
 248             SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0);
 249         }
 250     }
 251 }
 252 
 253 /* Restores the inheritance flag of handles from stored values. */
 254 static void restoreIOEHandleState(
 255     const HANDLE *stdIOE,
 256     const BOOL *inherit)
 257 {
 258     /* The set of current process standard IOE handles and
 259        the set of child process IOE handles can intersect.
 260        To restore the inherit flag right, we use backward
 261        array iteration. */
 262     int i;
 263     for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i)
 264         if (INVALID_HANDLE_VALUE != stdIOE[i]) {
 265            /* Restore inherit flag for any case.
 266               The handle can be changed by explicit inheritance.*/
 267             SetHandleInformation(stdIOE[i],
 268                 HANDLE_FLAG_INHERIT,
 269                 inherit[i] ? HANDLE_FLAG_INHERIT : 0);
 270         }
 271 }
 272 
 273 /* Please, read about the MS inheritance problem
 274    http://support.microsoft.com/kb/315939
 275    and critical section/synchronized block solution. */
 276 static jlong processCreate(
 277     JNIEnv *env,
 278     const jchar *pcmd,
 279     const jchar *penvBlock,
 280     const jchar *pdir,
 281     jlong *handles,
 282     jboolean redirectErrorStream)
 283 {
 284     jlong ret = 0L;
 285     STARTUPINFOW si = {sizeof(si)};
 286 
 287     /* Handles for which the inheritance flag must be restored. */
 288     HANDLE stdIOE[HANDLE_STORAGE_SIZE] = {
 289         /* Current process standard IOE handles: JDK-7147084 */
 290         INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE,
 291         /* Child process IOE handles: JDK-6921885 */
 292         (HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]};
 293     BOOL inherit[HANDLE_STORAGE_SIZE] = {
 294         FALSE, FALSE, FALSE,
 295         FALSE, FALSE, FALSE};
 296 
 297     {
 298         /* Extraction of current process standard IOE handles */
 299         DWORD idsIOE[3] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE};
 300         int i;
 301         for (i = 0; i < 3; ++i)
 302             /* Should not be closed by CloseHandle! */
 303             stdIOE[i] = GetStdHandle(idsIOE[i]);
 304     }
 305 
 306     prepareIOEHandleState(stdIOE, inherit);
 307     {
 308         /* Input */
 309         STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ};
 310         if (initHolder(env, &handles[0], &holderIn, &si.hStdInput)) {
 311 
 312             /* Output */
 313             STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
 314             if (initHolder(env, &handles[1], &holderOut, &si.hStdOutput)) {
 315 
 316                 /* Error */
 317                 STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE};
 318                 BOOL success;
 319                 if (redirectErrorStream) {
 320                     si.hStdError = si.hStdOutput;
 321                     /* Here we set the error stream to [ProcessBuilder.NullInputStream.INSTANCE]
 322                        value. That is in accordance with Java Doc for the redirection case.
 323                        The Java file for the [ handles[2] ] will be closed in ANY case. It is not
 324                        a handle leak. */
 325                     handles[2] = JAVA_INVALID_HANDLE_VALUE;
 326                     success = TRUE;
 327                 } else {
 328                     success = initHolder(env, &handles[2], &holderErr, &si.hStdError);


 329                 }







 330 
 331                 if (success) {
 332                     PROCESS_INFORMATION pi;
 333                     DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT;
 334 
 335                     si.dwFlags = STARTF_USESTDHANDLES;
 336                     if (!CreateProcessW(
 337                         NULL,             /* executable name */
 338                         (LPWSTR)pcmd,     /* command line */
 339                         NULL,             /* process security attribute */
 340                         NULL,             /* thread security attribute */
 341                         TRUE,             /* inherits system handles */
 342                         processFlag,      /* selected based on exe type */
 343                         (LPVOID)penvBlock,/* environment block */
 344                         (LPCWSTR)pdir,    /* change to the new current directory */
 345                         &si,              /* (in)  startup information */
 346                         &pi))             /* (out) process information */
 347                     {
 348                         win32Error(env, "CreateProcess");
 349                     } else {
 350                         closeSafely(pi.hThread);
 351                         ret = (jlong)pi.hProcess;
 352                     }
 353                 }
 354                 releaseHolder(ret == 0, &holderErr);
 355                 releaseHolder(ret == 0, &holderOut);
 356             }
 357             releaseHolder(ret == 0, &holderIn);
 358         }
 359     }
 360     restoreIOEHandleState(stdIOE, inherit);
 361 
 362     return ret;
 363 }
 364 
 365 JNIEXPORT jlong JNICALL
 366 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
 367                                   jstring cmd,
 368                                   jstring envBlock,
 369                                   jstring dir,
 370                                   jlongArray stdHandles,
 371                                   jboolean redirectErrorStream)
 372 {
 373     jlong ret = 0;
 374     if (cmd != NULL && stdHandles != NULL) {
 375         const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL);
 376         if (pcmd != NULL) {
 377             const jchar *penvBlock = (envBlock != NULL)
 378                 ? (*env)->GetStringChars(env, envBlock, NULL)
 379                 : NULL;
 380             const jchar *pdir = (dir != NULL)
 381                 ? (*env)->GetStringChars(env, dir, NULL)
 382                 : NULL;
 383             jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL);
 384             if (handles != NULL) {
 385                 ret = processCreate(
 386                     env,
 387                     pcmd,
 388                     penvBlock,
 389                     pdir,
 390                     handles,
 391                     redirectErrorStream);
 392                 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
 393             }
 394             if (pdir != NULL)
 395                 (*env)->ReleaseStringChars(env, dir, pdir);
 396             if (penvBlock != NULL)
 397                 (*env)->ReleaseStringChars(env, envBlock, penvBlock);
 398             (*env)->ReleaseStringChars(env, cmd, pcmd);
 399         }
 400     }
 401     return ret;







 402 }
 403 
 404 JNIEXPORT jint JNICALL
 405 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
 406 {
 407     DWORD exit_code;
 408     if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
 409         win32Error(env, "GetExitCodeProcess");
 410     return exit_code;
 411 }
 412 
 413 JNIEXPORT jint JNICALL
 414 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
 415 {
 416     return STILL_ACTIVE;
 417 }
 418 
 419 JNIEXPORT void JNICALL
 420 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
 421 {