Microsoft KB Archive/315939

= PRB: Child Inherits Unintended Handles During CreateProcess Call =

Article ID: 315939

Article Last Modified on 11/21/2006

-

APPLIES TO

 Microsoft Win32 Application Programming Interface, when used with:  Microsoft Windows XP Professional

 Microsoft Windows 2000 Standard Edition

 Microsoft Windows NT 4.0 

-

<div class="notice_section">

This article was previously published under Q315939

<div class="symptoms_section">

SYMPTOMS
When you create a child process by using the CreateProcess function call in a multithreaded environment, the child may inherit handles that were not intended to be inherited.

<div class="cause_section">

CAUSE
This behavior can occur if two threads simultaneously create child processes and redirect the STD handles through pipes. In this scenario, there is a race condition during the creation of the pipes and processes, in which it is possible for one child to inherit file handles intended for the other child. One thread creates the pipes, and while that thread is in the process of creating the process, the other thread is also creating a child process. All handles that are inheritable in the application during the CreateProcess call are duplicated across to the child process.

<div class="resolution_section">

RESOLUTION
To work around this issue, wrap the child-creation code in a critical section. This prevents any accidental inheritance. For this method to work properly, create the pipes as noninheritable by setting the security descriptor to NULL. Then, set the ends of the pipe that you want the child to inherit as inheritable by using the SetHandleInformation function call, as demonstrated in the following sample code: CRITICAL_SECTION   cs; HANDLE             hReadIn, hWriteIn; HANDLE             hReadOut, hWriteOut; HANDLE             hReadErr, hWriteErr;

InitializeCriticalSection(&cs);

EnterCriticalSection(&cs);

if ( !CreatePipe(&hReadIn, &hWriteIn, NULL, 0) ) {   // an error occurred }

if ( !CreatePipe(&hReadOut, &hWriteOut, NULL, 0) ) {   // an error occurred }

if ( !CreatePipe(&hReadErr, &hWriteErr, NULL, 0) ) {   // an error occurred }

if ( !SetHandleInformation(hReadIn, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ) {   // an error occurred }

if ( !SetHandleInformation(hWriteOut, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ) {   // an error occurred }

if ( !SetHandleInformation(hWriteErr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ) {   // an error occurred }

STARTUP_INFO       si; PROCESS_INFORMATION pi;

si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = hReadIn; si.hStdOutput = hWriteOut; si.hStdError = hWriteErr;

if ( !CreateProcess( &quot;child.exe&quot;, NULL, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, lpEnvironment, &si, &pi) ) {   // an error occurred }

CloseHandle(hReadIn); CloseHandle(hWriteOut); CloseHandle(hWriteErr);

LeaveCriticalSection(&cs); Note that the preceding solution does not come without costs. The creation of critical sections in code is sometimes messy and comes at a price of degraded performance. There is another workaround to this issue, and it requires the creation of an intermediate application to launch the child. However, this solution also has its downside. The main disadvantage to this method is that the parent basically loses the ease with which it obtains the child's process ID. If the parent needs the process ID, the intermediate process must pass it back somehow.

By using this intermediate application method, you avoid any accidental inheritance by relying on Windows to do the work for you. Any accidentally inherited handles in the intermediate process will definitely not be duplicated across to the child. This is guaranteed if you specify FALSE for the bInheritHandles parameter in the call to CreateProcess in the intermediate application. Your pipe handles will still be duplicated because Windows will always duplicate the STD handles, even when bInheritHandles is set to FALSE.

Parent Application
HANDLE             hReadIn, hWriteIn; HANDLE             hReadOut, hWriteOut; HANDLE             hReadErr, hWriteErr;

if ( !CreatePipe(&hReadIn, &hWriteIn, NULL, 0) ) {   // an error occurred }

if ( !CreatePipe(&hReadOut, &hWriteOut, NULL, 0) ) {   // an error occurred }

if ( !CreatePipe(&hReadErr, &hWriteErr, NULL, 0) ) {   // an error occurred }

STARTUP_INFO       si; PROCESS_INFORMATION pi;

si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = hReadIn; si.hStdOutput = hWriteOut; si.hStdError = hWriteErr;

if ( !CreateProcess( &quot;Intermediate.exe&quot;, NULL, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, lpEnvironment, &si, &pi) ) {   // an error occurred }

CloseHandle(hReadIn); CloseHandle(hWriteOut); CloseHandle(hWriteErr);

Intermediate Application
STARTUP_INFO       si; PROCESS_INFORMATION pi;

si.cb = sizeof(si);

if ( !CreateProcess( &quot;child.exe&quot;, NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, lpEnvironment, &si, &pi) ) {   // an error occurred }

Keywords: kbapi kbkernbase kbprb kbthread KB315939

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.