-
Notifications
You must be signed in to change notification settings - Fork 13.3k
windows: when creating process with redirected stdio, make parent's std handles not inheritable #54760
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Mucking about with enabling and disabling inheritance on handles is inherently racy and a bad idea. We really just need to implement the solution in https://blogs.msdn.microsoft.com/oldnewthing/20111216-00/?p=8873 |
@ikostia Only handles expressly passed to a child process should be inherited. The rest should not. This also applies to other platforms. |
This can be trivially solved if #38227 were implemented. |
I wanted to add a failure mode which made this important to me. I was trying to use command::spawn to start a process that outlives mine. It works from console but if stdout is piped then my process is held open until the spawned process is complete - breaking the expected behaviour of spawn. Calling the following function operates as a workaround for now: #[cfg(target_os = "windows")]
/// Disables inheritance on the inout pipe handles.
fn disable_handle_inheritance() {
use windows::Win32::Foundation::{SetHandleInformation, HANDLE_FLAGS, HANDLE_FLAG_INHERIT};
use windows::Win32::System::Console::{
GetStdHandle, STD_ERROR_HANDLE, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE,
};
unsafe {
let std_err = GetStdHandle(STD_ERROR_HANDLE);
let std_in = GetStdHandle(STD_INPUT_HANDLE);
let std_out = GetStdHandle(STD_OUTPUT_HANDLE);
for handle in [std_err, std_in, std_out] {
SetHandleInformation(handle, HANDLE_FLAG_INHERIT.0, HANDLE_FLAGS(0));
}
}
} |
Summary: When test runner waits for `buck2` process it hangs because buckd process is still running. This happens because buckd inherits handles from parent process and wait on the parent process awaits for these handles to be closed. Example: https://stackoverflow.com/questions/13243807/popen-waiting-for-child-process-even-when-the-immediate-child-has-terminated `Popen` in Python has `close_fds` argument to solve this: > On Windows, if close_fds is true then no handles will be inherited by the child process unless explicitly passed in the handle_list element of STARTUPINFO.lpAttributeList, or by standard handle redirection. https://docs.python.org/3/library/subprocess.html Rust sets `bInheritHandles` to `TRUE` unconditionally: https://github.com/rust-lang/rust/blob/acb5c16fa8acf7fd3b48fc218881f006577bab1a/library/std/src/sys/windows/process.rs#L327 There are several open issues related to this: - rust-lang/rust#54760 - rust-lang/rust#38227 Because of that we have to call `CreateProcessW` ourselves. Implementation is inspired by: - std library: https://github.com/rust-lang/rust/blob/master/library/std/src/sys/windows/process.rs - subprocess library: https://github.com/hniksic/rust-subprocess/blob/master/src/win32.rs - docs for `CreateProcessW`: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw Reviewed By: stepancheg Differential Revision: D36663797 fbshipit-source-id: 14431002a763042f9c160b8a7ff7f8a62dd6befa
I ran into this as well. Adding another example where this is an issue. In containerd a shim process is created and run to completion listening to the stdout. That process is often implemented to be short lived and responsible for some set up, and then it should create a new long lived process. Because containerd is listening to STDOUT this caused containerd to hang when spawning the long lived process. Even though the short live process completed, the inherited handle was causing a hang until the new child process completed. The work around above did help. The issue seems to come from always passing rust/library/std/src/sys/windows/process.rs Lines 326 to 331 in 439292b
|
Currently, if this happens:
the
child.exe
accidentally inherits stdin, stdout and stderr handles of the parent process. This can be bad, because the objects these handles point to (say pipes), may be watched by some third process.Since at the point of creating a child process we know that it does not need our std handles (because it's explicitly being created with
Stdio::null()
), we can temporarily disable handle inheritance on these handles.The text was updated successfully, but these errors were encountered: