Thread: CreateProcess variable definition

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Registered User Ktulu's Avatar
    Join Date
    Oct 2006
    Posts
    107

    CreateProcess variable definition

    When calling CreateProcess you can use the StartupInfo and ProcessInformation structures to specify/retrieve some extra information about the process being created. In a lot of examples you'll see something like this:

    Code:
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
    
        ZeroMemory( &si, sizeof(si) );
        si.cb = sizeof(si);
        ZeroMemory( &pi, sizeof(pi) );
    
        CreateProcess(...);
    Which is kind of surprising to me since I don't see any remarks about this on the corresponding MSDN page.

    I understand that if you're creating a process that makes use of the StartupInfo struct it is important to make sure that StartupInfo struct being passed doesn't contain any garbage data. So even if you don't need to specify any StartupInfo options this struct should be zero'd if the process being created depends on it.

    But this doesn't seem to be the case with the ProcessInformation struct. The system will fill all the members of this struct with the appropriate information and it's up to the caller to decide what to do with it.

    Question 1: If you're absolutely certain that the process being created will not do anything with the StartupInfo struct, is it safe to pass it to CreateProcess while containing garbage data?

    Question 2: Why zero the ProcessInformation struct before calling CreateProcess when the system will always fill this struct with the appropriate information? Shouldn't it be perfectly fine to pass this struct while it contains garbage data in any case?

    Question 3: In the situation described above is it correct to define/declare these structs as such before calling CreateProcess?

    Code:
        STARTUPINFO si = { sizeof(si) };
        PROCESS_INFORMATION pi;
    
        CreateProcess(...);
    This parameter is reserved

  2. #2
    Registered User
    Join Date
    Apr 2013
    Posts
    1,658
    I usually set the handles (first two members) of process information to INVALID_HANDLE_VALUE, in case CreateProcess() fails. At program exit, I check those two handles and if not equal to INVALID_HANDLE_VALUE, I close them. I also set the two id's to zero, but this probably isn't needed.

  3. #3
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    1/2 - I'm not sure it matters. It's good practice to zero things out for these types of api's anyway.

    3 - I wouldn't make any assumptions about member positions.

    Here's a utility function I use:
    Code:
    bool run(const wchar_t *cmd, PROCESS_INFORMATION *pi/*=0*/, bool bHide/*=true*/,
             const wchar_t *cmd_line/*=0*/)
    {
        // CreateProcess() needs a non-const string for 2nd param
        const wchar_t *p1 = 0;
        wchar_t p2[MAX_PATH * 2] = {0};
        
        if (cmd_line)
        {
            p1 = cmd;
            lstrcpyW(p2, cmd_line);
        }//if
        else
        {
            p1 = 0;
            lstrcpyW(p2, cmd);
        }//else
    
        PROCESS_INFORMATION ProcInfo = {0};
        STARTUPINFOW si = {0};
    
        si.cb = sizeof(si);
        
        if (bHide)
        {
            si.dwFlags = STARTF_USESHOWWINDOW;
            si.wShowWindow = SW_HIDE;
        }//if
    
        BOOL bSuccess;
        bSuccess = CreateProcessW(p1, p2, 0, 0, FALSE, 0, 0, 0, &si, &ProcInfo); 
        if (!bSuccess)
        {
            LogMessage(L"CreateProcess(%ls %ls) failed, le = %u", 
                       cmd, cmd_line ? cmd_line : L"", GetLastError()); 
            return false;
        }//if
        else
        {
            LogMessage(L"Run(%ls %ls)", cmd, cmd_line ? cmd_line : L"");
        }//else
    
        if (pi)
        {
            // caller is responsible for closing handles
            *pi = ProcInfo;
        }//if
        else
        {
            CloseHandle(ProcInfo.hThread);
            CloseHandle(ProcInfo.hProcess);
        }//else
    
        return true;
    }//run
    gg

  4. #4
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    Quote Originally Posted by Ktulu View Post
    If you're absolutely certain that the process being created will not do anything with the StartupInfo struct, is it safe to pass it to CreateProcess while containing garbage data?
    Check the documentation. If said parameter is marked "out" then yes, but if it's marked "in-out" then no.

  5. #5
    Registered User Ktulu's Avatar
    Join Date
    Oct 2006
    Posts
    107
    Quote Originally Posted by Yarin View Post
    Check the documentation. If said parameter is marked "out" then yes, but if it's marked "in-out" then no.
    How can you be certain that passing the StartupInfo struct (which is marked "in") while containing garbage data is unsafe when the process being created will never do anything with it?
    This parameter is reserved

  6. #6
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by Ktulu View Post
    How can you be certain that passing the StartupInfo struct (which is marked "in") while containing garbage data is unsafe when the process being created will never do anything with it?
    Why bother guessing? If the created process does read from uninitialized memory, then the behavior is indeterminate.

  7. #7
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    Quote Originally Posted by Ktulu View Post
    How can you be certain that passing the StartupInfo struct (which is marked "in") while containing garbage data is unsafe when the process being created will never do anything with it?
    "in" means it's going to be read by the calling function. What you or the new process does with it afterwards is irrelevant.

  8. #8
    Registered User Ktulu's Avatar
    Join Date
    Oct 2006
    Posts
    107
    I guess it's not specified if CreateProcess will do anything with the StartupInfo parameter before this data will become available to the newly created process. So passing the StartupInfo struct while it contains garbage data to CreateProcess could result in undefined behaviour. This should be avoided and so, as Yarin states, it becomes irrelevant whether the newly created process does anything with the provided StartupInfo data.

    But why do all the examples regarding the use of CreateProcess zero the ProcessInformation struct as well before passing it to CreateProcess other than good practice?
    This parameter is reserved

  9. #9
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Avoiding undefined behavior is reason enough to initialize.

  10. #10
    Registered User Ktulu's Avatar
    Join Date
    Oct 2006
    Posts
    107
    So passing an uninitialized output argument could cause undefined behaviour?
    This parameter is reserved

  11. #11
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by Ktulu View Post
    So passing an uninitialized output argument could cause undefined behaviour?
    Technically it could. Bad actors could assume CreateProcess succeeds, and if PROCESS_INFORMATION is uninitialized, the garbage may be read, introducing undefined behavior.

    Feel free to remain unsatisfied with good practice, perhaps I phrased it poorly, but it is easier to prove that a program works when you know the state of the variables from beginning to end.
    Last edited by whiteflags; 09-21-2015 at 09:00 PM.

  12. #12
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    Quote Originally Posted by Ktulu View Post
    So passing an uninitialized output argument could cause undefined behaviour?
    The documentation is very clear that CreateProcesses reads the struct. This means that if you don't initialize it, it might (read: will) have random garbage values, which CreateProcess will think are real. This is the paragon of undefined behavior.

  13. #13
    Registered User Ktulu's Avatar
    Join Date
    Oct 2006
    Posts
    107
    Where does the documentation say that it reads the ProcessInformation struct? The documentation says:

    lpProcessInformation [out]
    A pointer to a PROCESS_INFORMATION structure that receives identification information about the new process.
    This gives me the impression that there will only be information written to the ProcessInformation struct about a newly created process. Thus leaving garbage values in the ProcessInformation struct will result in the same behaviour as setting everything to zero before passing it to CreateProcess.
    This parameter is reserved

  14. #14
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    Quote Originally Posted by Ktulu View Post
    Where does the documentation say that it reads the ProcessInformation struct?
    You asked me about StartupInfo, not ProcessInformation.

    But even so, I would still zero out ProcessInformation. That way if CreateProcess fails I can still use an handle out of the struct. Like Codeplug demonstrated, it's not exactly hard to do it.

  15. #15
    Registered User Ktulu's Avatar
    Join Date
    Oct 2006
    Posts
    107
    I should have been more specific when I referred to "an uninitialized output argument".

    Quote Originally Posted by Yarin View Post
    But even so, I would still zero out ProcessInformation. That way if CreateProcess fails I can still use an handle out of the struct. Like Codeplug demonstrated, it's not exactly hard to do it.
    That depends a lot on the situation how CreateProcess is being used. When CreateProcess fails it might not have altered the ProcessInformation struct. If you then decide to call CloseHandle with the hProcess and hThread members of ProcessInformation (which makes no sense to me) it might result in undefined behaviour, assuming ProcessInformation is left with garbage values.

    But if in some situation the parent process relies on the successful creation of the new process, meaning it would terminate otherwise, there is absolutely no need to pass the ProcessInformation struct initialized with zero values.
    This parameter is reserved

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Declaration and definition of an external variable.
    By Mr.Lnx in forum C Programming
    Replies: 3
    Last Post: 01-12-2014, 03:02 AM
  2. Declaration and definition of a variable
    By raghu_1991 in forum C Programming
    Replies: 2
    Last Post: 05-11-2013, 02:21 AM
  3. Dynamic variable type definition
    By baxy in forum C++ Programming
    Replies: 3
    Last Post: 12-12-2012, 11:52 PM
  4. Mutual header inclusion breaks variable definition
    By Alexandre in forum C++ Programming
    Replies: 4
    Last Post: 08-22-2011, 10:03 AM
  5. Variable declaration Vs definition
    By callkalpa in forum C Programming
    Replies: 11
    Last Post: 12-17-2009, 12:21 PM