Skip to content

Commit 18f9a79

Browse files
committed
std: Lift out Windows' CreateProcess lock a bit
The function `CreateProcess` is not itself unsafe to call from many threads, the article in question is pointing out that handles can be inherited by unintended child processes. This is basically the same race as the standard Unix open-then-set-cloexec race. Since the intention of the lock is to protect children from inheriting unintended handles, the lock is now lifted out to before the creation of the child I/O handles (which will all be inheritable). This will ensure that we only have one process in Rust at least creating inheritable handles at a time, preventing unintended inheritance to children.
1 parent b8bd8f3 commit 18f9a79

File tree

1 file changed

+20
-13
lines changed

1 file changed

+20
-13
lines changed

src/libstd/sys/windows/process.rs

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,6 @@ impl Process {
159159
si.cb = mem::size_of::<c::STARTUPINFO>() as c::DWORD;
160160
si.dwFlags = c::STARTF_USESTDHANDLES;
161161

162-
let stdin = try!(in_handle.to_handle(c::STD_INPUT_HANDLE));
163-
let stdout = try!(out_handle.to_handle(c::STD_OUTPUT_HANDLE));
164-
let stderr = try!(err_handle.to_handle(c::STD_ERROR_HANDLE));
165-
166-
si.hStdInput = stdin.raw();
167-
si.hStdOutput = stdout.raw();
168-
si.hStdError = stderr.raw();
169-
170162
let program = program.as_ref().unwrap_or(&cfg.program);
171163
let mut cmd_str = try!(make_command_line(program, &cfg.args));
172164
cmd_str.push(0); // add null terminator
@@ -180,12 +172,27 @@ impl Process {
180172
let (envp, _data) = try!(make_envp(cfg.env.as_ref()));
181173
let (dirp, _data) = try!(make_dirp(cfg.cwd.as_ref()));
182174
let mut pi = zeroed_process_information();
183-
try!(unsafe {
184-
// `CreateProcess` is racy!
185-
// http://support.microsoft.com/kb/315939
186-
static CREATE_PROCESS_LOCK: StaticMutex = StaticMutex::new();
187-
let _lock = CREATE_PROCESS_LOCK.lock();
188175

176+
// Prepare all stdio handles to be inherited by the child. This
177+
// currently involves duplicating any existing ones with the ability to
178+
// be inherited by child processes. Note, however, that once an
179+
// inheritable handle is created, *any* spawned child will inherit that
180+
// handle. We only want our own child to inherit this handle, so we wrap
181+
// the remaining portion of this spawn in a mutex.
182+
//
183+
// For more information, msdn also has an article about this race:
184+
// http://support.microsoft.com/kb/315939
185+
static CREATE_PROCESS_LOCK: StaticMutex = StaticMutex::new();
186+
let _lock = CREATE_PROCESS_LOCK.lock();
187+
188+
let stdin = try!(in_handle.to_handle(c::STD_INPUT_HANDLE));
189+
let stdout = try!(out_handle.to_handle(c::STD_OUTPUT_HANDLE));
190+
let stderr = try!(err_handle.to_handle(c::STD_ERROR_HANDLE));
191+
si.hStdInput = stdin.raw();
192+
si.hStdOutput = stdout.raw();
193+
si.hStdError = stderr.raw();
194+
195+
try!(unsafe {
189196
cvt(c::CreateProcessW(ptr::null(),
190197
cmd_str.as_mut_ptr(),
191198
ptr::null_mut(),

0 commit comments

Comments
 (0)