--- old/src/windows/native/java/lang/ProcessImpl_md.c 2013-05-16 13:23:13.658400000 +0400 +++ new/src/windows/native/java/lang/ProcessImpl_md.c 2013-05-16 13:23:11.661600000 +0400 @@ -63,6 +63,200 @@ CloseHandle(handle); } +static BOOL hasInheritFlag(HANDLE handle) +{ + DWORD mask; + if (GetHandleInformation(handle, &mask)) { + return mask & HANDLE_FLAG_INHERIT; + } + return FALSE; +} + +#define HANDLE_STORAGE_SIZE 6 +#define OFFSET_READ 0 +#define OFFSET_WRITE 1 +#define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ) + +typedef struct _STDHOLDER { + HANDLE pipe[2]; + int offset; +} STDHOLDER; + +static BOOL initHolder( + JNIEnv *env, + STDHOLDER *pHolder, + jlong *pjhandles, + HANDLE *phStd) +{ + if (*pjhandles != (jlong) -1) { + *phStd = (HANDLE) *pjhandles; + *pjhandles = (jlong) -1; + } else { + if (!CreatePipe( + &pHolder->pipe[OFFSET_READ], + &pHolder->pipe[OFFSET_WRITE], + NULL, /* we would like to inherit + default process access, + instead of 'Everybody' access */ + PIPE_SIZE)) + { + win32Error(env, "CreatePipe"); + return FALSE; + } else { + /* [thisProcessEnd] has no the inherit flag. + the [lpPipeAttributes] param had the NULL value. */ + HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)]; + *phStd = pHolder->pipe[pHolder->offset]; + *pjhandles = (jlong) thisProcessEnd; + } + } + /* Pipe handle will be closed in the [releaseHolder] call, + file handle will be closed in Java. + The long-live handle need to restore the inherit flag, + we do it later in the [prepareIOEHandleState] call. */ + SetHandleInformation( + *phStd, + HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); + return TRUE; +} + +static void releaseHolder(BOOL complete, STDHOLDER *pHolder) { + closeSafely(pHolder->pipe[pHolder->offset]); + if (complete) { + /* Error occur, close this process pipe end */ + closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]); + } +} + +static void prepareIOEHandleState( + HANDLE *stdIOE, + BOOL *inherit) +{ + int i; + for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) { + HANDLE hstd = stdIOE[i]; + if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) { + /* FALSE by default */ + inherit[i] = TRUE; + /* Java does not need implicit inheritance for IOE handles, + so we drop inherit flag that probably was installed by + previous CreateProcess call that launched current process. + We will return the handle state back after CreateProcess call. + By clearing inherit flag we prevent "greedy grandchild" birth. + The explicit inheritance for child process IOE handles is + supported in the [initHolder] call. */ + SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0); + } + } +} + +static void restoreIOEHandleState( + const HANDLE *stdIOE, + const BOOL *inherit) +{ + /* The set of current process standard IOE handles and + the set of child process IOE handles can intersect. + To restore the inherit flag right, we use backward + array iteration. */ + int i; + for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i) + if (INVALID_HANDLE_VALUE != stdIOE[i]) { + /* Restore inherit flag for any case. + The handle can be changed by explicit inheritance.*/ + SetHandleInformation(stdIOE[i], + HANDLE_FLAG_INHERIT, + inherit[i] ? HANDLE_FLAG_INHERIT : 0); + } +} + +/* Please, read about the MS inheritance problem + http://support.microsoft.com/kb/315939 + and critical section/synchronized block solution. */ +static jlong processCreate( + JNIEnv *env, + const jchar *pcmd, + const jchar *penvBlock, + const jchar *pdir, + jlong *handles, + jboolean redirectErrorStream) +{ + jlong ret = 0L; + STARTUPINFOW si = {sizeof(si)}; + + /* Handles for which the inheritance flag must be restored. */ + HANDLE stdIOE[HANDLE_STORAGE_SIZE] = { + /* Current process standard IOE handles: JDK-7147084 */ + INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, + /* Child process IOE handles: JDK-6921885 */ + (HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]}; + BOOL inherit[HANDLE_STORAGE_SIZE] = { + FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE}; + + { + /* Extraction of current process standard IOE handles */ + DWORD idsIOE[3] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE}; + int i; + for (i = 0; i < 3; ++i) + /* Should not be closed by CloseHandle! */ + stdIOE[i] = GetStdHandle(idsIOE[i]); + } + + prepareIOEHandleState(stdIOE, inherit); + { + /* Input */ + STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ}; + if (initHolder(env, &holderIn, &handles[0], &si.hStdInput)) { + + /* Output */ + STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE}; + if (initHolder(env, &holderOut, &handles[1], &si.hStdOutput)) { + + /* Error */ + STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE}; + BOOL success; + if (redirectErrorStream) { + si.hStdError = si.hStdOutput; + handles[2] = (jlong) -1; + success = TRUE; + } else { + success = initHolder(env, &holderErr, &handles[2], &si.hStdError); + } + + if (success) { + PROCESS_INFORMATION pi; + DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; + + si.dwFlags = STARTF_USESTDHANDLES; + if (!CreateProcessW( + NULL, /* executable name */ + (LPWSTR)pcmd, /* command line */ + NULL, /* process security attribute */ + NULL, /* thread security attribute */ + TRUE, /* inherits system handles */ + processFlag, /* selected based on exe type */ + (LPVOID)penvBlock,/* environment block */ + (LPCWSTR)pdir, /* change to the new current directory */ + &si, /* (in) startup information */ + &pi)) /* (out) process information */ + { + win32Error(env, "CreateProcess"); + } else { + closeSafely(pi.hThread); + ret = (jlong)pi.hProcess; + } + } + releaseHolder(ret == 0, &holderErr); + releaseHolder(ret == 0, &holderOut); + } + releaseHolder(ret == 0, &holderIn); + } + } + restoreIOEHandleState(stdIOE, inherit); + + return ret; +} + JNIEXPORT jlong JNICALL Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, jstring cmd, @@ -71,138 +265,37 @@ jlongArray stdHandles, jboolean redirectErrorStream) { - HANDLE inRead = INVALID_HANDLE_VALUE; - HANDLE inWrite = INVALID_HANDLE_VALUE; - HANDLE outRead = INVALID_HANDLE_VALUE; - HANDLE outWrite = INVALID_HANDLE_VALUE; - HANDLE errRead = INVALID_HANDLE_VALUE; - HANDLE errWrite = INVALID_HANDLE_VALUE; - SECURITY_ATTRIBUTES sa; - PROCESS_INFORMATION pi; - STARTUPINFOW si; - const jchar* pcmd = NULL; - const jchar* pdir = NULL; - const jchar* penvBlock = NULL; - jlong *handles = NULL; jlong ret = 0; - DWORD processFlag; - - assert(cmd != NULL); - pcmd = (*env)->GetStringChars(env, cmd, NULL); - if (pcmd == NULL) goto Catch; - - if (dir != 0) { - pdir = (*env)->GetStringChars(env, dir, NULL); - if (pdir == NULL) goto Catch; - } - if (envBlock != NULL) { - penvBlock = ((*env)->GetStringChars(env, envBlock, NULL)); - if (penvBlock == NULL) goto Catch; - } - assert(stdHandles != NULL); - handles = (*env)->GetLongArrayElements(env, stdHandles, NULL); - if (handles == NULL) goto Catch; - - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - si.dwFlags = STARTF_USESTDHANDLES; - - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = 0; - sa.bInheritHandle = TRUE; - - if (handles[0] != (jlong) -1) { - si.hStdInput = (HANDLE) handles[0]; - handles[0] = (jlong) -1; - } else { - if (! CreatePipe(&inRead, &inWrite, &sa, PIPE_SIZE)) { - win32Error(env, "CreatePipe"); - goto Catch; - } - si.hStdInput = inRead; - SetHandleInformation(inWrite, HANDLE_FLAG_INHERIT, 0); - handles[0] = (jlong) inWrite; - } - SetHandleInformation(si.hStdInput, - HANDLE_FLAG_INHERIT, - HANDLE_FLAG_INHERIT); - - if (handles[1] != (jlong) -1) { - si.hStdOutput = (HANDLE) handles[1]; - handles[1] = (jlong) -1; - } else { - if (! CreatePipe(&outRead, &outWrite, &sa, PIPE_SIZE)) { - win32Error(env, "CreatePipe"); - goto Catch; + if (cmd != NULL + && stdHandles != NULL) + { + const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL); + if (pcmd != NULL) { + const jchar *penvBlock = (envBlock != NULL) + ? (*env)->GetStringChars(env, envBlock, NULL) + : NULL; + const jchar *pdir = (dir != NULL) + ? (*env)->GetStringChars(env, dir, NULL) + : NULL; + jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL); + if (handles != NULL) { + ret = processCreate( + env, + pcmd, + penvBlock, + pdir, + handles, + redirectErrorStream); + (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0); + } + if (pdir != NULL) + (*env)->ReleaseStringChars(env, dir, pdir); + if (penvBlock != NULL) + (*env)->ReleaseStringChars(env, envBlock, penvBlock); + (*env)->ReleaseStringChars(env, cmd, pcmd); } - si.hStdOutput = outWrite; - SetHandleInformation(outRead, HANDLE_FLAG_INHERIT, 0); - handles[1] = (jlong) outRead; - } - SetHandleInformation(si.hStdOutput, - HANDLE_FLAG_INHERIT, - HANDLE_FLAG_INHERIT); - - if (redirectErrorStream) { - si.hStdError = si.hStdOutput; - handles[2] = (jlong) -1; - } else if (handles[2] != (jlong) -1) { - si.hStdError = (HANDLE) handles[2]; - handles[2] = (jlong) -1; - } else { - if (! CreatePipe(&errRead, &errWrite, &sa, PIPE_SIZE)) { - win32Error(env, "CreatePipe"); - goto Catch; - } - si.hStdError = errWrite; - SetHandleInformation(errRead, HANDLE_FLAG_INHERIT, 0); - handles[2] = (jlong) errRead; - } - SetHandleInformation(si.hStdError, - HANDLE_FLAG_INHERIT, - HANDLE_FLAG_INHERIT); - - processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; - ret = CreateProcessW(0, /* executable name */ - (LPWSTR)pcmd, /* command line */ - 0, /* process security attribute */ - 0, /* thread security attribute */ - TRUE, /* inherits system handles */ - processFlag, /* selected based on exe type */ - (LPVOID)penvBlock,/* environment block */ - (LPCWSTR)pdir, /* change to the new current directory */ - &si, /* (in) startup information */ - &pi); /* (out) process information */ - if (!ret) { - win32Error(env, "CreateProcess"); - goto Catch; - } - - CloseHandle(pi.hThread); - ret = (jlong)pi.hProcess; - - Finally: - /* Always clean up the child's side of the pipes */ - closeSafely(inRead); - closeSafely(outWrite); - closeSafely(errWrite); - - if (pcmd != NULL) - (*env)->ReleaseStringChars(env, cmd, pcmd); - if (pdir != NULL) - (*env)->ReleaseStringChars(env, dir, pdir); - if (penvBlock != NULL) - (*env)->ReleaseStringChars(env, envBlock, penvBlock); - if (handles != NULL) - (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0); + } return ret; - - Catch: - /* Clean up the parent's side of the pipes in case of failure only */ - closeSafely(inWrite); - closeSafely(outRead); - closeSafely(errRead); - goto Finally; } JNIEXPORT jint JNICALL @@ -263,7 +356,7 @@ Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle) { DWORD dwExitStatus; - GetExitCodeProcess(handle, &dwExitStatus); + GetExitCodeProcess((HANDLE) handle, &dwExitStatus); return dwExitStatus == STILL_ACTIVE; }