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

Print this page
rev 7704 : 8016579: (process) IOException thrown by ProcessBuilder.start() method is incorrectly encoded


  95                     && buffer[0] == 'M' && buffer[1] == 'Z'
  96                     && _lseek(fd, 60L, SEEK_SET) == 60L
  97                     && _read(fd, buffer, 2) == 2)
  98                 {
  99                     long headerLoc = (long)buffer[1] << 8 | (long)buffer[0];
 100                     if (_lseek(fd, headerLoc, SEEK_SET) == headerLoc
 101                         && _read(fd, buffer, 2) == 2
 102                         && buffer[0] == 'P' && buffer[1] == 'E')
 103                     {
 104                         newFlag = DETACHED_PROCESS;
 105                     }
 106                 }
 107                 _close(fd);
 108             }
 109         }
 110         JNU_ReleaseStringPlatformChars(env, cmd0, exe);
 111     }
 112     return newFlag;
 113 }
 114 































 115 static void
 116 win32Error(JNIEnv *env, const char *functionName)
 117 {
 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


 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 


 332                     PROCESS_INFORMATION pi;
 333                     DWORD processFlag = CREATE_UNICODE_ENVIRONMENT;
 334 
 335                     /* Suppress popping-up of a console window for non-console applications */
 336                     if (GetConsoleWindow() == NULL)
 337                         processFlag |= CREATE_NO_WINDOW;
 338 
 339                     si.dwFlags = STARTF_USESTDHANDLES;
 340                     if (!CreateProcessW(
 341                         NULL,             /* executable name */
 342                         (LPWSTR)pcmd,     /* command line */
 343                         NULL,             /* process security attribute */
 344                         NULL,             /* thread security attribute */
 345                         TRUE,             /* inherits system handles */
 346                         processFlag,      /* selected based on exe type */
 347                         (LPVOID)penvBlock,/* environment block */
 348                         (LPCWSTR)pdir,    /* change to the new current directory */
 349                         &si,              /* (in)  startup information */
 350                         &pi))             /* (out) process information */
 351                     {
 352                         win32Error(env, "CreateProcess");
 353                     } else {
 354                         closeSafely(pi.hThread);
 355                         ret = (jlong)pi.hProcess;
 356                     }
 357                 }
 358                 releaseHolder(ret == 0, &holderErr);
 359                 releaseHolder(ret == 0, &holderOut);
 360             }
 361             releaseHolder(ret == 0, &holderIn);
 362         }
 363     }
 364     restoreIOEHandleState(stdIOE, inherit);
 365 
 366     return ret;
 367 }
 368 
 369 JNIEXPORT jlong JNICALL
 370 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
 371                                   jstring cmd,
 372                                   jstring envBlock,


 393                     pdir,
 394                     handles,
 395                     redirectErrorStream);
 396                 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
 397             }
 398             if (pdir != NULL)
 399                 (*env)->ReleaseStringChars(env, dir, pdir);
 400             if (penvBlock != NULL)
 401                 (*env)->ReleaseStringChars(env, envBlock, penvBlock);
 402             (*env)->ReleaseStringChars(env, cmd, pcmd);
 403         }
 404     }
 405     return ret;
 406 }
 407 
 408 JNIEXPORT jint JNICALL
 409 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
 410 {
 411     DWORD exit_code;
 412     if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
 413         win32Error(env, "GetExitCodeProcess");
 414     return exit_code;
 415 }
 416 
 417 JNIEXPORT jint JNICALL
 418 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
 419 {
 420     return STILL_ACTIVE;
 421 }
 422 
 423 JNIEXPORT void JNICALL
 424 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
 425 {
 426     HANDLE events[2];
 427     events[0] = (HANDLE) handle;
 428     events[1] = JVM_GetThreadInterruptEvent();
 429 
 430     if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
 431                                FALSE,    /* Wait for ANY event */
 432                                INFINITE) /* Wait forever */
 433         == WAIT_FAILED)
 434         win32Error(env, "WaitForMultipleObjects");
 435 }
 436 
 437 JNIEXPORT void JNICALL
 438 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
 439 {
 440     TerminateProcess((HANDLE) handle, 1);
 441 }
 442 
 443 JNIEXPORT jboolean JNICALL
 444 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
 445 {
 446     return CloseHandle((HANDLE) handle);
 447 }
 448 
 449 /**
 450  * Returns a copy of the Unicode characters of a string. Fow now this
 451  * function doesn't handle long path names and other issues.
 452  */
 453 static WCHAR* getPath(JNIEnv *env, jstring ps) {
 454     WCHAR *pathbuf = NULL;




  95                     && buffer[0] == 'M' && buffer[1] == 'Z'
  96                     && _lseek(fd, 60L, SEEK_SET) == 60L
  97                     && _read(fd, buffer, 2) == 2)
  98                 {
  99                     long headerLoc = (long)buffer[1] << 8 | (long)buffer[0];
 100                     if (_lseek(fd, headerLoc, SEEK_SET) == headerLoc
 101                         && _read(fd, buffer, 2) == 2
 102                         && buffer[0] == 'P' && buffer[1] == 'E')
 103                     {
 104                         newFlag = DETACHED_PROCESS;
 105                     }
 106                 }
 107                 _close(fd);
 108             }
 109         }
 110         JNU_ReleaseStringPlatformChars(env, cmd0, exe);
 111     }
 112     return newFlag;
 113 }
 114 
 115 /* We have THREE locales in action:
 116  * 1. Thread default locale - dictates UNICODE-to-8bit conversion
 117  * 2. System locale that defines the message localization
 118  * 3. The file name locale
 119  * Each locale could be an extended locale, that means that text cannot be
 120  * mapped to 8bit sequence without multibyte encoding.
 121  * VM is ready for that, if text is UTF-8.
 122  * Here we make the work right from the beginning.
 123  */
 124 size_t os_error_message(int errnum, WCHAR* utf16_OSErrorMsg, size_t maxMsgLength) {
 125     size_t n = (size_t)FormatMessageW(
 126             FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
 127             NULL,
 128             (DWORD)errnum,
 129             0,
 130             utf16_OSErrorMsg,
 131             (DWORD)maxMsgLength,
 132             NULL);
 133     if (n > 3) {
 134         // Drop final '.', CR, LF
 135         if (utf16_OSErrorMsg[n - 1] == L'\n') --n;
 136         if (utf16_OSErrorMsg[n - 1] == L'\r') --n;
 137         if (utf16_OSErrorMsg[n - 1] == L'.') --n;
 138         utf16_OSErrorMsg[n] = L'\0';
 139     }
 140     return n;
 141 }
 142 
 143 #define MESSAGE_LENGTH (256 + 100)
 144 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
 145 
 146 static void
 147 win32Error(JNIEnv *env, const WCHAR *functionName)
 148 {
 149     WCHAR utf16_OSErrorMsg[MESSAGE_LENGTH - 100];
 150     WCHAR utf16_javaMessage[MESSAGE_LENGTH];
 151     /*Good suggestion about 2-bytes-per-symbol in localized error reports*/
 152     char  utf8_javaMessage[MESSAGE_LENGTH*2];
 153     const int errnum = (int)GetLastError();
 154     int n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg));
 155     n = (n > 0)
 156         ? swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s error=%d, %s", functionName, errnum, utf16_OSErrorMsg)
 157         : swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s failed, error=%d", functionName, errnum);
 158 
 159     if (n > 0) /*terminate '\0' is not a part of conversion procedure*/
 160         n = WideCharToMultiByte(
 161             CP_UTF8,
 162             0,
 163             utf16_javaMessage,
 164             n, /*by creation n <= MESSAGE_LENGTH*/
 165             utf8_javaMessage,
 166             MESSAGE_LENGTH*2,
 167             NULL,
 168             NULL);
 169 
 170     /*no way to die*/
 171     {
 172         const char *errorMessage = "Secondary error while OS message extraction";
 173         if (n > 0) {
 174             utf8_javaMessage[min(MESSAGE_LENGTH*2 - 1, n)] = '\0';
 175             errorMessage = utf8_javaMessage;
 176         }
 177         JNU_ThrowIOException(env, errorMessage);
 178     }
 179 }
 180 
 181 static void
 182 closeSafely(HANDLE handle)
 183 {
 184     if (handle != INVALID_HANDLE_VALUE)
 185         CloseHandle(handle);
 186 }
 187 
 188 static BOOL hasInheritFlag(HANDLE handle)
 189 {
 190     DWORD mask;
 191     if (GetHandleInformation(handle, &mask)) {
 192         return mask & HANDLE_FLAG_INHERIT;
 193     }
 194     return FALSE;
 195 }
 196 
 197 #define HANDLE_STORAGE_SIZE 6
 198 #define OFFSET_READ  0


 226        value   0x00000000FFFFFFFF
 227        instead 0xFFFFFFFFFFFFFFFF. */
 228     if (*pjhandles != JAVA_INVALID_HANDLE_VALUE) {
 229         /* Java file or console redirection */
 230         *phStd = (HANDLE) *pjhandles;
 231         /* Here we set the related Java stream (Process.getXXXXStream())
 232            to [ProcessBuilder.NullXXXXStream.INSTANCE] value.
 233            The initial Java handle [*pjhandles] will be closed in
 234            ANY case. It is not a handle leak. */
 235         *pjhandles = JAVA_INVALID_HANDLE_VALUE;
 236     } else {
 237         /* Creation of parent-child pipe */
 238         if (!CreatePipe(
 239             &pHolder->pipe[OFFSET_READ],
 240             &pHolder->pipe[OFFSET_WRITE],
 241             NULL, /* we would like to inherit
 242                      default process access,
 243                      instead of 'Everybody' access */
 244             PIPE_SIZE))
 245         {
 246             win32Error(env, L"CreatePipe");
 247             return FALSE;
 248         } else {
 249             /* [thisProcessEnd] has no the inherit flag because
 250                the [lpPipeAttributes] param of [CreatePipe]
 251                had the NULL value. */
 252             HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)];
 253             *phStd = pHolder->pipe[pHolder->offset];
 254             *pjhandles = (jlong) thisProcessEnd;
 255         }
 256     }
 257     /* Pipe handle will be closed in the [releaseHolder] call,
 258        file handle will be closed in Java.
 259        The long-live handle need to restore the inherit flag,
 260        we do it later in the [prepareIOEHandleState] call. */
 261     SetHandleInformation(
 262         *phStd,
 263         HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
 264     return TRUE;
 265 }
 266 


 382                     PROCESS_INFORMATION pi;
 383                     DWORD processFlag = CREATE_UNICODE_ENVIRONMENT;
 384 
 385                     /* Suppress popping-up of a console window for non-console applications */
 386                     if (GetConsoleWindow() == NULL)
 387                         processFlag |= CREATE_NO_WINDOW;
 388 
 389                     si.dwFlags = STARTF_USESTDHANDLES;
 390                     if (!CreateProcessW(
 391                         NULL,             /* executable name */
 392                         (LPWSTR)pcmd,     /* command line */
 393                         NULL,             /* process security attribute */
 394                         NULL,             /* thread security attribute */
 395                         TRUE,             /* inherits system handles */
 396                         processFlag,      /* selected based on exe type */
 397                         (LPVOID)penvBlock,/* environment block */
 398                         (LPCWSTR)pdir,    /* change to the new current directory */
 399                         &si,              /* (in)  startup information */
 400                         &pi))             /* (out) process information */
 401                     {
 402                         win32Error(env, L"CreateProcess");
 403                     } else {
 404                         closeSafely(pi.hThread);
 405                         ret = (jlong)pi.hProcess;
 406                     }
 407                 }
 408                 releaseHolder(ret == 0, &holderErr);
 409                 releaseHolder(ret == 0, &holderOut);
 410             }
 411             releaseHolder(ret == 0, &holderIn);
 412         }
 413     }
 414     restoreIOEHandleState(stdIOE, inherit);
 415 
 416     return ret;
 417 }
 418 
 419 JNIEXPORT jlong JNICALL
 420 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
 421                                   jstring cmd,
 422                                   jstring envBlock,


 443                     pdir,
 444                     handles,
 445                     redirectErrorStream);
 446                 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
 447             }
 448             if (pdir != NULL)
 449                 (*env)->ReleaseStringChars(env, dir, pdir);
 450             if (penvBlock != NULL)
 451                 (*env)->ReleaseStringChars(env, envBlock, penvBlock);
 452             (*env)->ReleaseStringChars(env, cmd, pcmd);
 453         }
 454     }
 455     return ret;
 456 }
 457 
 458 JNIEXPORT jint JNICALL
 459 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
 460 {
 461     DWORD exit_code;
 462     if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
 463         win32Error(env, L"GetExitCodeProcess");
 464     return exit_code;
 465 }
 466 
 467 JNIEXPORT jint JNICALL
 468 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
 469 {
 470     return STILL_ACTIVE;
 471 }
 472 
 473 JNIEXPORT void JNICALL
 474 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
 475 {
 476     HANDLE events[2];
 477     events[0] = (HANDLE) handle;
 478     events[1] = JVM_GetThreadInterruptEvent();
 479 
 480     if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
 481                                FALSE,    /* Wait for ANY event */
 482                                INFINITE) /* Wait forever */
 483         == WAIT_FAILED)
 484         win32Error(env, L"WaitForMultipleObjects");
 485 }
 486 
 487 JNIEXPORT void JNICALL
 488 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
 489 {
 490     TerminateProcess((HANDLE) handle, 1);
 491 }
 492 
 493 JNIEXPORT jboolean JNICALL
 494 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
 495 {
 496     return CloseHandle((HANDLE) handle);
 497 }
 498 
 499 /**
 500  * Returns a copy of the Unicode characters of a string. Fow now this
 501  * function doesn't handle long path names and other issues.
 502  */
 503 static WCHAR* getPath(JNIEnv *env, jstring ps) {
 504     WCHAR *pathbuf = NULL;