in vm/vmcore/src/kernel_classes/native/Runtime_win.cpp [87:282]
void JNICALL Java_java_lang_Runtime_00024SubProcess_createProcess0 (
JNIEnv *env, jobject obj, jobjectArray cmdarray,
jobjectArray envp, jstring dir, jlongArray la)
{
TRACE("Creating child process ...");
HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup, hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
hChildStderrorRd, hChildStderrorWr, hChildStderrorRdDup;
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
SECURITY_ATTRIBUTES saAttr;
const char *strDir = NULL;
// Get the working directory of the subprocess:
if ( dir != NULL ) {
strDir = env->GetStringUTFChars(dir, 0);
}
// Get the the command to call and its arguments:
int btl = 1024;
int l = btl;
char *strCmnd = (char*)malloc(btl);
*strCmnd = '\0';
jsize len = env->GetArrayLength(cmdarray);
int cur_pos = 0;
int i;
for ( i = 0; i < len; i++ ) {
jstring jo = (jstring)env->GetObjectArrayElement(cmdarray, (jsize) i);
const char *strChain = env->GetStringUTFChars(jo, 0);
bool need_esc = (*strChain != '\"' && strchr(strChain, ' ') != NULL);
cur_pos += (int)strlen(strChain) + (i == 0 ? 0 : 1) + (need_esc ? 0 : 2);
while (l <= cur_pos) {
char *strtmp = (char*)malloc(l + btl);
memcpy(strtmp, strCmnd, l);
l += btl;
free((void *)strCmnd);
strCmnd = strtmp;
}
if ( i != 0 ) {
strcat(strCmnd, " ");
}
if (need_esc) strcat(strCmnd, "\"");
strcat(strCmnd, strChain);
if (need_esc) strcat(strCmnd, "\"");
env->ReleaseStringUTFChars(jo, strChain);
}
TRACE("Child process command-line : " << strCmnd);
char *strEnvp = NULL;
// Get the array, each element of which has environment variable settings:
if (envp != NULL) {
int l = btl;
strEnvp = (char*)malloc(btl);
*strEnvp = '\0';
len = env->GetArrayLength(envp);
cur_pos = 0;
for ( i = 0; i < len; i++ ) {
jstring jo = (jstring)env->GetObjectArrayElement(envp, (jsize) i);
const char* strChain = env->GetStringUTFChars(jo, 0);
int tmp = (int)strlen(strChain) + 1;
while (l <= (cur_pos + tmp)) {
char *strtmp = (char*)malloc(l + btl);
memcpy(strtmp, strEnvp, l);
l += btl;
free(strEnvp);
strEnvp = strtmp;
}
strcpy(strEnvp + cur_pos, strChain);
cur_pos += tmp;
env->ReleaseStringUTFChars(jo, strChain);
}
strEnvp[cur_pos++] = '\0';
}
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Preparation of the child process's STDOUT:
// 1. Create a pipe for the child process's STDOUT.
if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) {
Error("Stdout pipe creation failed\n", env, la);
return;
}
// 2. Create noninheritable read handle and close the inheritable read handle.
if( !DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, GetCurrentProcess(), &hChildStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS) ) {
CloseHandle(hChildStdoutRd);
CloseHandle(hChildStdoutWr);
Error("DuplicateHandle failed", env, la);
return;
}
CloseHandle(hChildStdoutRd);
// Preparation of the child process's STDERROR:
// 1. Create anonymous pipe to be STDERROR for child process.
if (! CreatePipe(&hChildStderrorRd, &hChildStderrorWr, &saAttr, 0)) {
CloseHandle(hChildStdoutRdDup);
CloseHandle(hChildStdoutWr);
Error("Stderror pipe creation failed\n", env, la);
return;
}
// 2. Create a noninheritable duplicate of the read handle, and close the inheritable read handle.
if( !DuplicateHandle(GetCurrentProcess(), hChildStderrorRd, GetCurrentProcess(), &hChildStderrorRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS) ) {
CloseHandle(hChildStdoutRdDup);
CloseHandle(hChildStdoutWr);
CloseHandle(hChildStderrorRd);
CloseHandle(hChildStderrorWr);
Error("DuplicateHandle failed", env, la);
return;
}
CloseHandle(hChildStderrorRd);
// Preparation of the child process's STDIN:
// 1. Create anonymous pipe to be STDIN for child process.
if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
CloseHandle(hChildStdoutRdDup);
CloseHandle(hChildStdoutWr);
CloseHandle(hChildStderrorRdDup);
CloseHandle(hChildStderrorWr);
Error("Stdin pipe creation failed\n", env, la);
return;
}
// 2. Create a noninheritable duplicate of the write handle, and close the inheritable write handle.
if ( !DuplicateHandle(GetCurrentProcess(), hChildStdinWr, GetCurrentProcess(), &hChildStdinWrDup, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
CloseHandle(hChildStdoutRdDup);
CloseHandle(hChildStdoutWr);
CloseHandle(hChildStderrorRdDup);
CloseHandle(hChildStderrorWr);
CloseHandle(hChildStdinRd);
CloseHandle(hChildStdinWr);
Error("DuplicateHandle failed", env, la);
return;
}
CloseHandle(hChildStdinWr);
// Now create the child process:
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = hChildStderrorWr;
siStartInfo.hStdOutput = hChildStdoutWr;
siStartInfo.hStdInput = hChildStdinRd;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
BOOL created = CreateProcess(NULL /* name of executable module */,
strCmnd /* command line */,
NULL /* process security attributes */,
NULL /* primary thread security attributes */,
TRUE /* handles are inherited */,
0 /* creation flags */,
strEnvp /* either use parent's environment or use the own one */,
strDir /* either use parent's current directory or use new one */,
&siStartInfo /* STARTUPINFO pointer */,
&piProcInfo /* receives PROCESS_INFORMATION */ );
if (!created) {
ErrorMsg();
Error("Process creation failed\n", env, la);
}
// Memory deallocation.
free(strCmnd);
if (strEnvp) {
free(strEnvp);
}
if (dir) {
env->ReleaseStringUTFChars(dir, strDir);
}
CloseHandle(hChildStdoutWr);
CloseHandle(hChildStderrorWr);
CloseHandle(hChildStdinRd);
if (created) {
CloseHandle(piProcInfo.hThread);
jlong *lp = (jlong*)env->GetLongArrayElements(la, 0);
lp[0] = (jlong) piProcInfo.hProcess;
lp[1] = (jlong) hChildStdinWrDup;
lp[2] = (jlong) hChildStdoutRdDup;
lp[3] = (jlong) hChildStderrorRdDup;
env->ReleaseLongArrayElements(la, lp, 0);
} else {
CloseHandle(hChildStdoutRdDup);
CloseHandle(hChildStderrorRdDup);
CloseHandle(hChildStdinWrDup);
}
}