Skip to content
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

proposal to support raw_attribute with raw pointer #124180

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions library/std/src/os/windows/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#![stable(feature = "process_extensions", since = "1.2.0")]

use core::ffi::c_void;

use crate::ffi::OsStr;
use crate::os::windows::io::{
AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
Expand Down Expand Up @@ -368,6 +370,14 @@ pub trait CommandExt: Sealed {
attribute: usize,
value: T,
) -> &mut process::Command;

#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
unsafe fn raw_attribute_ptr(
&mut self,
attribute: usize,
value_ptr: *const c_void,
value_size: usize,
) -> &mut process::Command;
}

#[stable(feature = "windows_process_extensions", since = "1.16.0")]
Expand Down Expand Up @@ -409,6 +419,18 @@ impl CommandExt for process::Command {
unsafe { self.as_inner_mut().raw_attribute(attribute, value) };
self
}

unsafe fn raw_attribute_ptr(
&mut self,
attribute: usize,
value_ptr: *const c_void,
value_size: usize,
) -> &mut process::Command {
unsafe {
self.as_inner_mut().raw_attribute_ptr(attribute, value_ptr, value_size);
}
self
}
}

#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
Expand Down
93 changes: 75 additions & 18 deletions library/std/src/sys/pal/windows/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,10 +253,28 @@ impl Command {
attribute: usize,
value: T,
) {
self.proc_thread_attributes.insert(attribute, ProcThreadAttributeValue {
size: mem::size_of::<T>(),
data: Box::new(value),
});
self.proc_thread_attributes.insert(
attribute,
ProcThreadAttributeValue::Data(ProcThreadAttributeValueData {
size: mem::size_of::<T>(),
data: Box::new(value),
}),
);
}

pub unsafe fn raw_attribute_ptr(
&mut self,
attribute: usize,
value_ptr: *const c_void,
value_size: usize,
) {
self.proc_thread_attributes.insert(
attribute,
ProcThreadAttributeValue::Pointer(ProcThreadAttributeValuePointer {
size: value_size,
pointer: value_ptr as isize,
}),
);
}

pub fn spawn(
Expand Down Expand Up @@ -336,12 +354,21 @@ impl Command {

let mut si = zeroed_startupinfo();

// if STARTF_USESTDHANDLES is not used with PSEUDOCONSOLE,
// it is not guaranteed that all the desired stdio of the new process are
// really connected to the new console.
// The problem + solution is described here:
// https://github.com/microsoft/terminal/issues/4380#issuecomment-580865346
const PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE: usize = 0x20016;
let force_use_std_handles =
self.proc_thread_attributes.contains_key(&PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE);

// If at least one of stdin, stdout or stderr are set (i.e. are non null)
// then set the `hStd` fields in `STARTUPINFO`.
// Otherwise skip this and allow the OS to apply its default behavior.
// This provides more consistent behavior between Win7 and Win8+.
let is_set = |stdio: &Handle| !stdio.as_raw_handle().is_null();
if is_set(&stderr) || is_set(&stdout) || is_set(&stdin) {
if force_use_std_handles || is_set(&stderr) || is_set(&stdout) || is_set(&stdin) {
si.dwFlags |= c::STARTF_USESTDHANDLES;
si.hStdInput = stdin.as_raw_handle();
si.hStdOutput = stdout.as_raw_handle();
Expand Down Expand Up @@ -907,11 +934,21 @@ impl Drop for ProcThreadAttributeList {
}

/// Wrapper around the value data to be used as a Process Thread Attribute.
struct ProcThreadAttributeValue {
struct ProcThreadAttributeValueData {
data: Box<dyn Send + Sync>,
size: usize,
}

struct ProcThreadAttributeValuePointer {
pointer: isize, // using isize instead of *const c_void to have it sendable
size: usize,
}

enum ProcThreadAttributeValue {
Data(ProcThreadAttributeValueData),
Pointer(ProcThreadAttributeValuePointer),
}

fn make_proc_thread_attribute_list(
attributes: &BTreeMap<usize, ProcThreadAttributeValue>,
) -> io::Result<ProcThreadAttributeList> {
Expand Down Expand Up @@ -953,18 +990,38 @@ fn make_proc_thread_attribute_list(
// It's theoretically possible for the attribute count to exceed a u32 value.
// Therefore, we ensure that we don't add more attributes than the buffer was initialized for.
for (&attribute, value) in attributes.iter().take(attribute_count as usize) {
let value_ptr = (&raw const *value.data) as _;
cvt(unsafe {
c::UpdateProcThreadAttribute(
proc_thread_attribute_list.0.as_mut_ptr() as _,
0,
attribute,
value_ptr,
value.size,
ptr::null_mut(),
ptr::null_mut(),
)
})?;
match value {
ProcThreadAttributeValue::Data(value) => {
let value_ptr = (&raw const *value.data) as _;
cvt(unsafe {
c::UpdateProcThreadAttribute(
proc_thread_attribute_list.0.as_mut_ptr() as _,
0,
attribute,
value_ptr,
value.size,
ptr::null_mut(),
ptr::null_mut(),
)
})?;
}
ProcThreadAttributeValue::Pointer(value) => {
cvt(
unsafe {
#![allow(fuzzy_provenance_casts)]
c::UpdateProcThreadAttribute(
proc_thread_attribute_list.0.as_mut_ptr() as _,
0,
attribute,
value.pointer as *const c_void,
value.size,
ptr::null_mut(),
ptr::null_mut(),
)
},
)?;
}
}
}

Ok(proc_thread_attribute_list)
Expand Down
Loading