Thread: CreateProcess variable definition

  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
    Registered User Ktulu's Avatar
    Join Date
    Oct 2006
    Posts
    107
    Because to me setting the ProcesInformation structure to zero before passing to CreateProcess feels like:

    Code:
    char buff[buffsize];
    
    ZeroMemory( buff, sizeof(buff) );
    
    strcpy( buff, something );
    This parameter is reserved

  13. #13
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Honestly, I've noticed a couple of things while talking to you:

    a) We have to pretend that there is some force preventing you from editing examples as you see fit; including, but not limited to, initializing only what you find necessary.

    b) We have to pretend that initializing memory takes a lot of time and needs to be optimized.

  14. #14
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> ... to me setting the ProcesInformation structure to zero before passing to CreateProcess feels like ...
    Setting 0 to a structure is simple, and demonstrated above:
    Code:
        ...
        PROCESS_INFORMATION ProcInfo = {0};
        STARTUPINFOW si = {0};
        ...
    gg

  15. #15
    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.

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