Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit acbac23

Browse files
committedSep 9, 2024
Abstract ProcThreadAttributeList into its own struct
1 parent e08b80c commit acbac23

File tree

3 files changed

+284
-151
lines changed

3 files changed

+284
-151
lines changed
 

‎library/std/src/os/windows/process.rs

Lines changed: 263 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
55
#![stable(feature = "process_extensions", since = "1.2.0")]
66

7-
use crate::ffi::OsStr;
7+
use crate::ffi::{c_void, OsStr};
8+
use crate::mem::MaybeUninit;
89
use crate::os::windows::io::{
910
AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
1011
};
1112
use crate::sealed::Sealed;
1213
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
13-
use crate::{process, sys};
14+
use crate::{io, marker, process, ptr, sys};
1415

1516
#[stable(feature = "process_extensions", since = "1.2.0")]
1617
impl FromRawHandle for process::Stdio {
@@ -295,41 +296,26 @@ pub trait CommandExt: Sealed {
295296
#[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")]
296297
fn async_pipes(&mut self, always_async: bool) -> &mut process::Command;
297298

298-
/// Set a raw attribute on the command, providing extended configuration options for Windows
299-
/// processes.
299+
/// Executes the command as a child process with the given
300+
/// [`ProcThreadAttributeList`], returning a handle to it.
300301
///
301-
/// This method allows you to specify custom attributes for a child process on Windows systems
302-
/// using raw attribute values. Raw attributes provide extended configurability for process
303-
/// creation, but their usage can be complex and potentially unsafe.
304-
///
305-
/// The `attribute` parameter specifies the raw attribute to be set, while the `value`
306-
/// parameter holds the value associated with that attribute. Please refer to the
307-
/// [`windows-rs` documentation] or the [Win32 API documentation] for detailed information
308-
/// about available attributes and their meanings.
309-
///
310-
/// [`windows-rs` documentation]: https://microsoft.github.io/windows-docs-rs/doc/windows/
311-
/// [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute
302+
/// This method enables the customization of attributes for the spawned
303+
/// child process on Windows systems.
304+
/// Attributes offer extended configurability for process creation,
305+
/// but their usage can be intricate and potentially unsafe.
312306
///
313307
/// # Note
314308
///
315-
/// The maximum number of raw attributes is the value of [`u32::MAX`].
316-
/// If this limit is exceeded, the call to [`process::Command::spawn`] will return an `Error`
317-
/// indicating that the maximum number of attributes has been exceeded.
318-
///
319-
/// # Safety
320-
///
321-
/// The usage of raw attributes is potentially unsafe and should be done with caution.
322-
/// Incorrect attribute values or improper configuration can lead to unexpected behavior or
323-
/// errors.
309+
/// By default, stdin, stdout, and stderr are inherited from the parent
310+
/// process.
324311
///
325312
/// # Example
326313
///
327-
/// The following example demonstrates how to create a child process with a specific parent
328-
/// process ID using a raw attribute.
329-
///
330-
/// ```rust
314+
/// ```
331315
/// #![feature(windows_process_extensions_raw_attribute)]
332-
/// use std::os::windows::{process::CommandExt, io::AsRawHandle};
316+
/// use std::os::windows::process::ProcThreadAttributeList;
317+
/// use std::os::windows::process::CommandExt;
318+
/// use std::os::windows::io::AsRawHandle;
333319
/// use std::process::Command;
334320
///
335321
/// # struct ProcessDropGuard(std::process::Child);
@@ -338,36 +324,27 @@ pub trait CommandExt: Sealed {
338324
/// # let _ = self.0.kill();
339325
/// # }
340326
/// # }
341-
///
327+
/// #
342328
/// let parent = Command::new("cmd").spawn()?;
343-
///
344-
/// let mut child_cmd = Command::new("cmd");
329+
/// let parent_process_handle = parent.as_raw_handle();
330+
/// # let parent = ProcessDropGuard(parent);
345331
///
346332
/// const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000;
333+
/// let mut attribute_list = ProcThreadAttributeList::build()
334+
/// .attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_process_handle)
335+
/// .finish()
336+
/// .unwrap();
347337
///
348-
/// unsafe {
349-
/// child_cmd.raw_attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parent.as_raw_handle() as isize);
350-
/// }
338+
/// let mut child = Command::new("cmd").spawn_with_attributes(attribute_list)?;
351339
/// #
352-
/// # let parent = ProcessDropGuard(parent);
353-
///
354-
/// let mut child = child_cmd.spawn()?;
355-
///
356340
/// # child.kill()?;
357341
/// # Ok::<(), std::io::Error>(())
358342
/// ```
359-
///
360-
/// # Safety Note
361-
///
362-
/// Remember that improper use of raw attributes can lead to undefined behavior or security
363-
/// vulnerabilities. Always consult the documentation and ensure proper attribute values are
364-
/// used.
365343
#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
366-
unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
344+
fn spawn_with_attributes(
367345
&mut self,
368-
attribute: usize,
369-
value: T,
370-
) -> &mut process::Command;
346+
attribute_list: &ProcThreadAttributeList<'_>,
347+
) -> io::Result<process::Child>;
371348
}
372349

373350
#[stable(feature = "windows_process_extensions", since = "1.16.0")]
@@ -401,13 +378,13 @@ impl CommandExt for process::Command {
401378
self
402379
}
403380

404-
unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
381+
fn spawn_with_attributes(
405382
&mut self,
406-
attribute: usize,
407-
value: T,
408-
) -> &mut process::Command {
409-
unsafe { self.as_inner_mut().raw_attribute(attribute, value) };
410-
self
383+
attribute_list: &ProcThreadAttributeList<'_>,
384+
) -> io::Result<process::Child> {
385+
self.as_inner_mut()
386+
.spawn_with_attributes(sys::process::Stdio::Inherit, true, Some(attribute_list))
387+
.map(process::Child::from_inner)
411388
}
412389
}
413390

@@ -447,3 +424,234 @@ impl ExitCodeExt for process::ExitCode {
447424
process::ExitCode::from_inner(From::from(raw))
448425
}
449426
}
427+
428+
/// A wrapper around windows [`ProcThreadAttributeList`][1].
429+
///
430+
/// [1]: <https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-initializeprocthreadattributelist>
431+
#[derive(Debug)]
432+
#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
433+
pub struct ProcThreadAttributeList<'a> {
434+
attribute_list: Box<[MaybeUninit<u8>]>,
435+
_lifetime_marker: marker::PhantomData<&'a ()>,
436+
}
437+
438+
#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
439+
impl<'a> ProcThreadAttributeList<'a> {
440+
/// Creates a new builder for constructing a [`ProcThreadAttributeList`].
441+
pub fn build() -> ProcThreadAttributeListBuilder<'a> {
442+
ProcThreadAttributeListBuilder::new()
443+
}
444+
445+
/// Returns a pointer to the underling attribute list.
446+
#[doc(hidden)]
447+
pub fn as_ptr(&self) -> *const MaybeUninit<u8> {
448+
self.attribute_list.as_ptr()
449+
}
450+
}
451+
452+
#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
453+
impl<'a> Drop for ProcThreadAttributeList<'a> {
454+
/// Deletes the attribute list.
455+
///
456+
/// This method calls [`DeleteProcThreadAttributeList`][1] to delete the
457+
/// underlying attribute list.
458+
///
459+
/// [1]: <https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-deleteprocthreadattributelist>
460+
fn drop(&mut self) {
461+
let lp_attribute_list = self.attribute_list.as_mut_ptr().cast::<c_void>();
462+
unsafe { sys::c::DeleteProcThreadAttributeList(lp_attribute_list) }
463+
}
464+
}
465+
466+
/// Builder for constructing a [`ProcThreadAttributeList`].
467+
#[derive(Clone, Debug)]
468+
#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
469+
pub struct ProcThreadAttributeListBuilder<'a> {
470+
attributes: alloc::collections::BTreeMap<usize, ProcThreadAttributeValue>,
471+
_lifetime_marker: marker::PhantomData<&'a ()>,
472+
}
473+
474+
#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
475+
impl<'a> ProcThreadAttributeListBuilder<'a> {
476+
fn new() -> Self {
477+
ProcThreadAttributeListBuilder {
478+
attributes: alloc::collections::BTreeMap::new(),
479+
_lifetime_marker: marker::PhantomData,
480+
}
481+
}
482+
483+
/// Sets an attribute on the attribute list.
484+
///
485+
/// The `attribute` parameter specifies the raw attribute to be set, while
486+
/// the `value` parameter holds the value associated with that attribute.
487+
/// Please refer to the [Windows documentation][1] for a list of valid attributes.
488+
///
489+
/// # Note
490+
///
491+
/// The maximum number of attributes is the value of [`u32::MAX`]. If this
492+
/// limit is exceeded, the call to [`Self::finish`] will return an `Error`
493+
/// indicating that the maximum number of attributes has been exceeded.
494+
///
495+
/// # Safety Note
496+
///
497+
/// Remember that improper use of attributes can lead to undefined behavior
498+
/// or security vulnerabilities. Always consult the documentation and ensure
499+
/// proper attribute values are used.
500+
///
501+
/// [1]: <https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute#parameters>
502+
pub fn attribute<T>(self, attribute: usize, value: &'a T) -> Self {
503+
unsafe {
504+
self.raw_attribute(
505+
attribute,
506+
ptr::addr_of!(*value).cast::<c_void>(),
507+
crate::mem::size_of::<T>(),
508+
)
509+
}
510+
}
511+
512+
/// Sets a raw attribute on the attribute list.
513+
///
514+
/// This function is useful for setting attributes with pointers or sizes
515+
/// that cannot be derived directly from their values.
516+
///
517+
/// # Safety
518+
///
519+
/// This function is marked as `unsafe` because it deals with raw pointers
520+
/// and sizes. It is the responsibility of the caller to ensure the value
521+
/// lives longer than the [`ProcThreadAttributeListBuilder`] as well as
522+
/// the validity of the size parameter.
523+
///
524+
/// # Example
525+
/// ```
526+
/// use std::ffi::c_void;
527+
/// use std::mem::{self, zeroed};
528+
/// use std::os::windows::process::ProcThreadAttributeList;
529+
/// use std::os::windows::process::CommandExt;
530+
/// use std::os::windows::raw::HANDLE;
531+
/// use std::process::Command;
532+
///
533+
/// #[repr(C)]
534+
/// pub struct COORD {
535+
/// pub X: i16,
536+
/// pub Y: i16,
537+
/// }
538+
///
539+
/// extern "system" {
540+
/// fn CreatePipe(hreadpipe: HANDLE, hwritepipe: HANDLE, lppipeattributes: *const c_void, nsize: u32) -> i32;
541+
/// fn CreatePseudoConsole(size: COORD, hinput: HANDLE, houtput: HANDLE, dwflags: u32, phpc: *mut isize) -> i32;
542+
/// fn CloseHandle(hobject: HANDLE) -> i32;
543+
/// }
544+
///
545+
/// let (mut input_read_side, mut output_write_side) = unsafe { (zeroed(), zeroed()) };
546+
/// let (mut output_read_side, mut input_write_side) = unsafe { (zeroed(), zeroed()) };
547+
///
548+
/// unsafe {
549+
/// CreatePipe(&mut input_read_side, &mut input_write_side, None, 0);
550+
/// CreatePipe(&mut output_read_side, &mut output_write_side, None, 0);
551+
/// }
552+
///
553+
/// let size = COORD { X: 60, Y: 40 };
554+
/// let mut h_pc = unsafe { zeroed() };
555+
/// unsafe { CreatePseudoConsole(size, input_read_side, output_write_side, 0, &mut h_pc) };
556+
///
557+
/// unsafe { CloseHandle(input_read_side) };
558+
/// unsafe { CloseHandle(output_write_side) };
559+
///
560+
/// const PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE: u32 = 131094u32;
561+
///
562+
/// let attribute_list = unsafe {
563+
/// ProcThreadAttributeList::build()
564+
/// .raw_attribute(
565+
/// PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
566+
/// h_pc as *const c_void,
567+
/// mem::size_of::<isize>()
568+
/// )
569+
/// .finish()
570+
/// };
571+
///
572+
/// let child = Command::new("cmd").spawn_with_attributes(attribute_list)?;
573+
/// #
574+
/// # child.kill()?;
575+
/// # Ok::<(), std::io::Error>(())
576+
/// ```
577+
pub unsafe fn raw_attribute<T>(
578+
mut self,
579+
attribute: usize,
580+
value_ptr: *const T,
581+
value_size: usize,
582+
) -> Self {
583+
self.attributes.insert(
584+
attribute,
585+
ProcThreadAttributeValue { ptr: value_ptr.cast::<c_void>(), size: value_size },
586+
);
587+
self
588+
}
589+
590+
/// Finalizes the construction of the `ProcThreadAttributeList`.
591+
///
592+
/// # Errors
593+
///
594+
/// Returns an error if the maximum number of attributes is exceeded
595+
/// or if there is an I/O error during initialization.
596+
pub fn finish(&self) -> io::Result<ProcThreadAttributeList<'a>> {
597+
// To initialize our ProcThreadAttributeList, we need to determine
598+
// how many bytes to allocate for it. The Windows API simplifies this
599+
// process by allowing us to call `InitializeProcThreadAttributeList`
600+
// with a null pointer to retrieve the required size.
601+
let mut required_size = 0;
602+
let Ok(attribute_count) = self.attributes.len().try_into() else {
603+
return Err(io::const_io_error!(
604+
io::ErrorKind::InvalidInput,
605+
"maximum number of ProcThreadAttributes exceeded",
606+
));
607+
};
608+
unsafe {
609+
sys::c::InitializeProcThreadAttributeList(
610+
ptr::null_mut(),
611+
attribute_count,
612+
0,
613+
&mut required_size,
614+
)
615+
};
616+
617+
let mut attribute_list = vec![MaybeUninit::uninit(); required_size].into_boxed_slice();
618+
619+
// Once we've allocated the necessary memory, it's safe to invoke
620+
// `InitializeProcThreadAttributeList` to properly initialize the list.
621+
sys::cvt(unsafe {
622+
sys::c::InitializeProcThreadAttributeList(
623+
attribute_list.as_mut_ptr().cast::<c_void>(),
624+
attribute_count,
625+
0,
626+
&mut required_size,
627+
)
628+
})?;
629+
630+
// # Add our attributes to the buffer.
631+
// It's theoretically possible for the attribute count to exceed a u32
632+
// value. Therefore, we ensure that we don't add more attributes than
633+
// the buffer was initialized for.
634+
for (&attribute, value) in self.attributes.iter().take(attribute_count as usize) {
635+
sys::cvt(unsafe {
636+
sys::c::UpdateProcThreadAttribute(
637+
attribute_list.as_mut_ptr().cast::<c_void>(),
638+
0,
639+
attribute,
640+
value.ptr,
641+
value.size,
642+
ptr::null_mut(),
643+
ptr::null_mut(),
644+
)
645+
})?;
646+
}
647+
648+
Ok(ProcThreadAttributeList { attribute_list, _lifetime_marker: marker::PhantomData })
649+
}
650+
}
651+
652+
/// Wrapper around the value data to be used as a Process Thread Attribute.
653+
#[derive(Clone, Debug)]
654+
struct ProcThreadAttributeValue {
655+
ptr: *const c_void,
656+
size: usize,
657+
}

‎library/std/src/process/tests.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ fn test_creation_flags() {
436436
fn test_proc_thread_attributes() {
437437
use crate::mem;
438438
use crate::os::windows::io::AsRawHandle;
439-
use crate::os::windows::process::CommandExt;
439+
use crate::os::windows::process::{CommandExt, ProcThreadAttributeList};
440440
use crate::sys::c::{CloseHandle, BOOL, HANDLE};
441441
use crate::sys::cvt;
442442

@@ -476,12 +476,14 @@ fn test_proc_thread_attributes() {
476476

477477
let mut child_cmd = Command::new("cmd");
478478

479-
unsafe {
480-
child_cmd
481-
.raw_attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parent.0.as_raw_handle() as isize);
482-
}
479+
let parent_process_handle = parent.0.as_raw_handle();
480+
481+
let mut attribute_list = ProcThreadAttributeList::build()
482+
.attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_process_handle)
483+
.finish()
484+
.unwrap();
483485

484-
let child = ProcessDropGuard(child_cmd.spawn().unwrap());
486+
let child = ProcessDropGuard(child_cmd.spawn_with_attributes(&mut attribute_list).unwrap());
485487

486488
let h_snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
487489

‎library/std/src/sys/pal/windows/process.rs

Lines changed: 13 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ use crate::collections::BTreeMap;
1010
use crate::env::consts::{EXE_EXTENSION, EXE_SUFFIX};
1111
use crate::ffi::{OsStr, OsString};
1212
use crate::io::{self, Error, ErrorKind};
13-
use crate::mem::MaybeUninit;
1413
use crate::num::NonZero;
1514
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
1615
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
16+
use crate::os::windows::process::ProcThreadAttributeList;
1717
use crate::path::{Path, PathBuf};
1818
use crate::sync::Mutex;
1919
use crate::sys::args::{self, Arg};
@@ -162,7 +162,6 @@ pub struct Command {
162162
stdout: Option<Stdio>,
163163
stderr: Option<Stdio>,
164164
force_quotes_enabled: bool,
165-
proc_thread_attributes: BTreeMap<usize, ProcThreadAttributeValue>,
166165
}
167166

168167
pub enum Stdio {
@@ -194,7 +193,6 @@ impl Command {
194193
stdout: None,
195194
stderr: None,
196195
force_quotes_enabled: false,
197-
proc_thread_attributes: Default::default(),
198196
}
199197
}
200198

@@ -248,21 +246,19 @@ impl Command {
248246
self.cwd.as_ref().map(Path::new)
249247
}
250248

251-
pub unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
249+
pub fn spawn(
252250
&mut self,
253-
attribute: usize,
254-
value: T,
255-
) {
256-
self.proc_thread_attributes.insert(
257-
attribute,
258-
ProcThreadAttributeValue { size: mem::size_of::<T>(), data: Box::new(value) },
259-
);
251+
default: Stdio,
252+
needs_stdin: bool,
253+
) -> io::Result<(Process, StdioPipes)> {
254+
self.spawn_with_attributes(default, needs_stdin, None)
260255
}
261256

262-
pub fn spawn(
257+
pub fn spawn_with_attributes(
263258
&mut self,
264259
default: Stdio,
265260
needs_stdin: bool,
261+
proc_thread_attribute_list: Option<&ProcThreadAttributeList<'_>>,
266262
) -> io::Result<(Process, StdioPipes)> {
267263
let maybe_env = self.env.capture_if_changed();
268264

@@ -342,18 +338,18 @@ impl Command {
342338

343339
let si_ptr: *mut c::STARTUPINFOW;
344340

345-
let mut proc_thread_attribute_list;
346341
let mut si_ex;
347342

348-
if !self.proc_thread_attributes.is_empty() {
343+
if let Some(proc_thread_attribute_list) = proc_thread_attribute_list {
349344
si.cb = mem::size_of::<c::STARTUPINFOEXW>() as u32;
350345
flags |= c::EXTENDED_STARTUPINFO_PRESENT;
351346

352-
proc_thread_attribute_list =
353-
make_proc_thread_attribute_list(&self.proc_thread_attributes)?;
354347
si_ex = c::STARTUPINFOEXW {
355348
StartupInfo: si,
356-
lpAttributeList: proc_thread_attribute_list.0.as_mut_ptr() as _,
349+
// SAFETY: Casting this `*const` pointer to a `*mut` pointer is "safe"
350+
// here because windows does not internally mutate the attribute list.
351+
// Ideally this should be reflected in the interface of the `windows-sys` crate.
352+
lpAttributeList: proc_thread_attribute_list.as_ptr().cast::<c_void>().cast_mut(),
357353
};
358354
si_ptr = core::ptr::addr_of_mut!(si_ex) as _;
359355
} else {
@@ -884,79 +880,6 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
884880
}
885881
}
886882

887-
struct ProcThreadAttributeList(Box<[MaybeUninit<u8>]>);
888-
889-
impl Drop for ProcThreadAttributeList {
890-
fn drop(&mut self) {
891-
let lp_attribute_list = self.0.as_mut_ptr() as _;
892-
unsafe { c::DeleteProcThreadAttributeList(lp_attribute_list) }
893-
}
894-
}
895-
896-
/// Wrapper around the value data to be used as a Process Thread Attribute.
897-
struct ProcThreadAttributeValue {
898-
data: Box<dyn Send + Sync>,
899-
size: usize,
900-
}
901-
902-
fn make_proc_thread_attribute_list(
903-
attributes: &BTreeMap<usize, ProcThreadAttributeValue>,
904-
) -> io::Result<ProcThreadAttributeList> {
905-
// To initialize our ProcThreadAttributeList, we need to determine
906-
// how many bytes to allocate for it. The Windows API simplifies this process
907-
// by allowing us to call `InitializeProcThreadAttributeList` with
908-
// a null pointer to retrieve the required size.
909-
let mut required_size = 0;
910-
let Ok(attribute_count) = attributes.len().try_into() else {
911-
return Err(io::const_io_error!(
912-
ErrorKind::InvalidInput,
913-
"maximum number of ProcThreadAttributes exceeded",
914-
));
915-
};
916-
unsafe {
917-
c::InitializeProcThreadAttributeList(
918-
ptr::null_mut(),
919-
attribute_count,
920-
0,
921-
&mut required_size,
922-
)
923-
};
924-
925-
let mut proc_thread_attribute_list =
926-
ProcThreadAttributeList(vec![MaybeUninit::uninit(); required_size].into_boxed_slice());
927-
928-
// Once we've allocated the necessary memory, it's safe to invoke
929-
// `InitializeProcThreadAttributeList` to properly initialize the list.
930-
cvt(unsafe {
931-
c::InitializeProcThreadAttributeList(
932-
proc_thread_attribute_list.0.as_mut_ptr() as *mut _,
933-
attribute_count,
934-
0,
935-
&mut required_size,
936-
)
937-
})?;
938-
939-
// # Add our attributes to the buffer.
940-
// It's theoretically possible for the attribute count to exceed a u32 value.
941-
// Therefore, we ensure that we don't add more attributes than the buffer was initialized for.
942-
for (&attribute, value) in attributes.iter().take(attribute_count as usize) {
943-
let value_ptr = core::ptr::addr_of!(*value.data) as _;
944-
cvt(unsafe {
945-
c::UpdateProcThreadAttribute(
946-
proc_thread_attribute_list.0.as_mut_ptr() as _,
947-
0,
948-
attribute,
949-
value_ptr,
950-
value.size,
951-
ptr::null_mut(),
952-
ptr::null_mut(),
953-
)
954-
})?;
955-
}
956-
957-
Ok(proc_thread_attribute_list)
958-
}
959-
960883
pub struct CommandArgs<'a> {
961884
iter: crate::slice::Iter<'a, Arg>,
962885
}

0 commit comments

Comments
 (0)
This repository has been archived.