void JNICALL Java_java_lang_Runtime_00024SubProcess_createProcess0()

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);
    }
}