diff options
| author | bors <bors@rust-lang.org> | 2023-08-29 05:55:46 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-08-29 05:55:46 +0000 |
| commit | d9c11c65ee93b6dfd0c71f17812c68d316fce183 (patch) | |
| tree | 1451f2e711b883122df8c5f3f7baa19ef46a1c89 /library/std | |
| parent | 63bf24090e38463bc2125170a0c3e98e0d20a85c (diff) | |
| parent | fb3565a848af21af18c26156f0acae9115257e46 (diff) | |
Auto merge of #3042 - rust-lang:rustup-2023-08-29, r=RalfJung
Automatic sync from rustc
Diffstat (limited to 'library/std')
| -rw-r--r-- | library/std/src/alloc.rs | 26 | ||||
| -rw-r--r-- | library/std/src/macros.rs | 12 | ||||
| -rw-r--r-- | library/std/src/os/unix/net/tests.rs | 2 | ||||
| -rw-r--r-- | library/std/src/os/windows/process.rs | 69 | ||||
| -rw-r--r-- | library/std/src/panicking.rs | 36 | ||||
| -rw-r--r-- | library/std/src/process/tests.rs | 85 | ||||
| -rw-r--r-- | library/std/src/sys/hermit/mod.rs | 1 | ||||
| -rw-r--r-- | library/std/src/sys/hermit/net.rs | 8 | ||||
| -rw-r--r-- | library/std/src/sys/unix/alloc.rs | 6 | ||||
| -rw-r--r-- | library/std/src/sys/windows/c/windows_sys.lst | 5 | ||||
| -rw-r--r-- | library/std/src/sys/windows/c/windows_sys.rs | 37 | ||||
| -rw-r--r-- | library/std/src/sys/windows/process.rs | 112 | ||||
| -rw-r--r-- | library/std/src/time.rs | 24 |
13 files changed, 399 insertions, 24 deletions
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 1eae7fa6a95..bb786bd59dc 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -290,15 +290,29 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); /// Registers a custom allocation error hook, replacing any that was previously registered. /// -/// The allocation error hook is invoked when an infallible memory allocation fails, before -/// the runtime aborts. The default hook prints a message to standard error, -/// but this behavior can be customized with the [`set_alloc_error_hook`] and -/// [`take_alloc_error_hook`] functions. +/// The allocation error hook is invoked when an infallible memory allocation fails — that is, +/// as a consequence of calling [`handle_alloc_error`] — before the runtime aborts. /// -/// The hook is provided with a `Layout` struct which contains information +/// The allocation error hook is a global resource. [`take_alloc_error_hook`] may be used to +/// retrieve a previously registered hook and wrap or discard it. +/// +/// # What the provided `hook` function should expect +/// +/// The hook function is provided with a [`Layout`] struct which contains information /// about the allocation that failed. /// -/// The allocation error hook is a global resource. +/// The hook function may choose to panic or abort; in the event that it returns normally, this +/// will cause an immediate abort. +/// +/// Since [`take_alloc_error_hook`] is a safe function that allows retrieving the hook, the hook +/// function must be _sound_ to call even if no memory allocations were attempted. +/// +/// # The default hook +/// +/// The default hook, used if [`set_alloc_error_hook`] is never called, prints a message to +/// standard error (and then returns, causing the runtime to abort the process). +/// Compiler options may cause it to panic instead, and the default behavior may be changed +/// to panicking in future versions of Rust. /// /// # Examples /// diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index ba1b8cbfa56..34b8b6b97b5 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -41,6 +41,9 @@ macro_rules! panic { /// Use `print!` only for the primary output of your program. Use /// [`eprint!`] instead to print error and progress messages. /// +/// See [the formatting documentation in `std::fmt`](../std/fmt/index.html) +/// for details of the macro argument syntax. +/// /// [flush]: crate::io::Write::flush /// [`println!`]: crate::println /// [`eprint!`]: crate::eprint @@ -103,6 +106,9 @@ macro_rules! print { /// Use `println!` only for the primary output of your program. Use /// [`eprintln!`] instead to print error and progress messages. /// +/// See [the formatting documentation in `std::fmt`](../std/fmt/index.html) +/// for details of the macro argument syntax. +/// /// [`std::fmt`]: crate::fmt /// [`eprintln!`]: crate::eprintln /// [lock]: crate::io::Stdout @@ -150,6 +156,9 @@ macro_rules! println { /// [`io::stderr`]: crate::io::stderr /// [`io::stdout`]: crate::io::stdout /// +/// See [the formatting documentation in `std::fmt`](../std/fmt/index.html) +/// for details of the macro argument syntax. +/// /// # Panics /// /// Panics if writing to `io::stderr` fails. @@ -181,6 +190,9 @@ macro_rules! eprint { /// Use `eprintln!` only for error and progress messages. Use `println!` /// instead for the primary output of your program. /// +/// See [the formatting documentation in `std::fmt`](../std/fmt/index.html) +/// for details of the macro argument syntax. +/// /// [`io::stderr`]: crate::io::stderr /// [`io::stdout`]: crate::io::stdout /// [`println!`]: crate::println diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs index 3d4302e665c..6a6af9efd78 100644 --- a/library/std/src/os/unix/net/tests.rs +++ b/library/std/src/os/unix/net/tests.rs @@ -662,7 +662,7 @@ fn test_send_vectored_fds_unix_stream() { } } -#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] +#[cfg(any(target_os = "android", target_os = "linux"))] #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets fn test_send_vectored_with_ancillary_to_unix_datagram() { diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 073168cf2d2..5d87216ff1b 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -192,6 +192,66 @@ pub trait CommandExt: Sealed { /// ``` #[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")] fn async_pipes(&mut self, always_async: bool) -> &mut process::Command; + + /// Sets a raw attribute on the command, providing extended configuration options for Windows processes. + /// + /// This method allows you to specify custom attributes for a child process on Windows systems using raw attribute values. + /// Raw attributes provide extended configurability for process creation, but their usage can be complex and potentially unsafe. + /// + /// The `attribute` parameter specifies the raw attribute to be set, while the `value` parameter holds the value associated with that attribute. + /// Please refer to the [`windows-rs`](https://microsoft.github.io/windows-docs-rs/doc/windows/) documentation or the [`Win32 API documentation`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute) for detailed information about available attributes and their meanings. + /// + /// # Note + /// + /// The maximum number of raw attributes is the value of [`u32::MAX`]. + /// If this limit is exceeded, the call to [`process::Command::spawn`] will return an `Error` indicating that the maximum number of attributes has been exceeded. + /// # Safety + /// + /// The usage of raw attributes is potentially unsafe and should be done with caution. Incorrect attribute values or improper configuration can lead to unexpected behavior or errors. + /// + /// # Example + /// + /// The following example demonstrates how to create a child process with a specific parent process ID using a raw attribute. + /// + /// ```rust + /// #![feature(windows_process_extensions_raw_attribute)] + /// use std::os::windows::{process::CommandExt, io::AsRawHandle}; + /// use std::process::Command; + /// + /// # struct ProcessDropGuard(std::process::Child); + /// # impl Drop for ProcessDropGuard { + /// # fn drop(&mut self) { + /// # let _ = self.0.kill(); + /// # } + /// # } + /// + /// let parent = Command::new("cmd").spawn()?; + /// + /// let mut child_cmd = Command::new("cmd"); + /// + /// const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000; + /// + /// unsafe { + /// child_cmd.raw_attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parent.as_raw_handle() as isize); + /// } + /// # + /// # let parent = ProcessDropGuard(parent); + /// + /// let mut child = child_cmd.spawn()?; + /// + /// # child.kill()?; + /// # Ok::<(), std::io::Error>(()) + /// ``` + /// + /// # Safety Note + /// + /// Remember that improper use of raw attributes can lead to undefined behavior or security vulnerabilities. Always consult the documentation and ensure proper attribute values are used. + #[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")] + unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>( + &mut self, + attribute: usize, + value: T, + ) -> &mut process::Command; } #[stable(feature = "windows_process_extensions", since = "1.16.0")] @@ -219,6 +279,15 @@ impl CommandExt for process::Command { let _ = always_async; self } + + unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>( + &mut self, + attribute: usize, + value: T, + ) -> &mut process::Command { + self.as_inner_mut().raw_attribute(attribute, value); + self + } } #[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")] diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 6ff7b19f293..b20e5464e6e 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -246,7 +246,9 @@ fn default_hook(info: &PanicInfo<'_>) { pub fn panic_hook_with_disk_dump(info: &PanicInfo<'_>, path: Option<&crate::path::Path>) { // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. - let backtrace = if panic_count::get_count() >= 2 { + let backtrace = if info.force_no_backtrace() { + None + } else if panic_count::get_count() >= 2 { BacktraceStyle::full() } else { crate::panic::get_backtrace_style() @@ -294,7 +296,7 @@ pub fn panic_hook_with_disk_dump(info: &PanicInfo<'_>, path: Option<&crate::path } } } - // If backtraces aren't supported, do nothing. + // If backtraces aren't supported or are forced-off, do nothing. None => {} } }; @@ -615,14 +617,23 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { let loc = info.location().unwrap(); // The current implementation always returns Some let msg = info.message().unwrap(); // The current implementation always returns Some crate::sys_common::backtrace::__rust_end_short_backtrace(move || { + // FIXME: can we just pass `info` along rather than taking it apart here, only to have + // `rust_panic_with_hook` construct a new `PanicInfo`? if let Some(msg) = msg.as_str() { - rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind()); + rust_panic_with_hook( + &mut StrPanicPayload(msg), + info.message(), + loc, + info.can_unwind(), + info.force_no_backtrace(), + ); } else { rust_panic_with_hook( &mut PanicPayload::new(msg), info.message(), loc, info.can_unwind(), + info.force_no_backtrace(), ); } }) @@ -647,7 +658,13 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! { let loc = Location::caller(); return crate::sys_common::backtrace::__rust_end_short_backtrace(move || { - rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc, true) + rust_panic_with_hook( + &mut PanicPayload::new(msg), + None, + loc, + /* can_unwind */ true, + /* force_no_backtrace */ false, + ) }); struct PanicPayload<A> { @@ -693,6 +710,7 @@ fn rust_panic_with_hook( message: Option<&fmt::Arguments<'_>>, location: &Location<'_>, can_unwind: bool, + force_no_backtrace: bool, ) -> ! { let must_abort = panic_count::increase(true); @@ -707,14 +725,20 @@ fn rust_panic_with_hook( panic_count::MustAbort::AlwaysAbort => { // Unfortunately, this does not print a backtrace, because creating // a `Backtrace` will allocate, which we must to avoid here. - let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind); + let panicinfo = PanicInfo::internal_constructor( + message, + location, + can_unwind, + force_no_backtrace, + ); rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n"); } } crate::sys::abort_internal(); } - let mut info = PanicInfo::internal_constructor(message, location, can_unwind); + let mut info = + PanicInfo::internal_constructor(message, location, can_unwind, force_no_backtrace); let hook = HOOK.read().unwrap_or_else(PoisonError::into_inner); match *hook { // Some platforms (like wasm) know that printing to stderr won't ever actually diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index 366b591466c..00636237288 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -434,6 +434,91 @@ fn test_creation_flags() { assert!(events > 0); } +/// Tests proc thread attributes by spawning a process with a custom parent process, +/// then comparing the parent process ID with the expected parent process ID. +#[test] +#[cfg(windows)] +fn test_proc_thread_attributes() { + use crate::mem; + use crate::os::windows::io::AsRawHandle; + use crate::os::windows::process::CommandExt; + use crate::sys::c::{CloseHandle, BOOL, HANDLE}; + use crate::sys::cvt; + + #[repr(C)] + #[allow(non_snake_case)] + struct PROCESSENTRY32W { + dwSize: u32, + cntUsage: u32, + th32ProcessID: u32, + th32DefaultHeapID: usize, + th32ModuleID: u32, + cntThreads: u32, + th32ParentProcessID: u32, + pcPriClassBase: i32, + dwFlags: u32, + szExeFile: [u16; 260], + } + + extern "system" { + fn CreateToolhelp32Snapshot(dwflags: u32, th32processid: u32) -> HANDLE; + fn Process32First(hsnapshot: HANDLE, lppe: *mut PROCESSENTRY32W) -> BOOL; + fn Process32Next(hsnapshot: HANDLE, lppe: *mut PROCESSENTRY32W) -> BOOL; + } + + const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000; + const TH32CS_SNAPPROCESS: u32 = 0x00000002; + + struct ProcessDropGuard(crate::process::Child); + + impl Drop for ProcessDropGuard { + fn drop(&mut self) { + let _ = self.0.kill(); + } + } + + let parent = ProcessDropGuard(Command::new("cmd").spawn().unwrap()); + + let mut child_cmd = Command::new("cmd"); + + unsafe { + child_cmd + .raw_attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parent.0.as_raw_handle() as isize); + } + + let child = ProcessDropGuard(child_cmd.spawn().unwrap()); + + let h_snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) }; + + let mut process_entry = PROCESSENTRY32W { + dwSize: mem::size_of::<PROCESSENTRY32W>() as u32, + cntUsage: 0, + th32ProcessID: 0, + th32DefaultHeapID: 0, + th32ModuleID: 0, + cntThreads: 0, + th32ParentProcessID: 0, + pcPriClassBase: 0, + dwFlags: 0, + szExeFile: [0; 260], + }; + + unsafe { cvt(Process32First(h_snapshot, &mut process_entry as *mut _)) }.unwrap(); + + loop { + if child.0.id() == process_entry.th32ProcessID { + break; + } + unsafe { cvt(Process32Next(h_snapshot, &mut process_entry as *mut _)) }.unwrap(); + } + + unsafe { cvt(CloseHandle(h_snapshot)) }.unwrap(); + + assert_eq!(parent.0.id(), process_entry.th32ParentProcessID); + + drop(child) +} + #[test] fn test_command_implements_send_sync() { fn take_send_sync_type<T: Send + Sync>(_: T) {} diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs index c7cb8466705..fb22d3e22cd 100644 --- a/library/std/src/sys/hermit/mod.rs +++ b/library/std/src/sys/hermit/mod.rs @@ -101,7 +101,6 @@ pub extern "C" fn __rust_abort() { // SAFETY: must be called only once during runtime initialization. // NOTE: this is not guaranteed to run, for example when Rust code is called externally. pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { - let _ = net::init(); args::init(argc, argv); } diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs index 8c2d489d6a3..bffda7a8139 100644 --- a/library/std/src/sys/hermit/net.rs +++ b/library/std/src/sys/hermit/net.rs @@ -33,13 +33,7 @@ pub fn cvt_gai(err: i32) -> io::Result<()> { )) } -/// Checks whether the HermitCore's socket interface has been started already, and -/// if not, starts it. -pub fn init() { - if unsafe { netc::network_init() } < 0 { - panic!("Unable to initialize network interface"); - } -} +pub fn init() {} #[derive(Debug)] pub struct Socket(FileDesc); diff --git a/library/std/src/sys/unix/alloc.rs b/library/std/src/sys/unix/alloc.rs index 8604b53983d..af0089978ec 100644 --- a/library/std/src/sys/unix/alloc.rs +++ b/library/std/src/sys/unix/alloc.rs @@ -86,7 +86,11 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "wasi")] { #[inline] unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - libc::aligned_alloc(layout.align(), layout.size()) as *mut u8 + // C11 aligned_alloc requires that the size be a multiple of the alignment. + // Layout already checks that the size rounded up doesn't overflow isize::MAX. + let align = layout.align(); + let size = layout.size().next_multiple_of(align); + libc::aligned_alloc(align, size) as *mut u8 } } else { #[inline] diff --git a/library/std/src/sys/windows/c/windows_sys.lst b/library/std/src/sys/windows/c/windows_sys.lst index 631aedd26b4..5469ba42eb1 100644 --- a/library/std/src/sys/windows/c/windows_sys.lst +++ b/library/std/src/sys/windows/c/windows_sys.lst @@ -2510,6 +2510,7 @@ Windows.Win32.System.Threading.CreateProcessW Windows.Win32.System.Threading.CreateThread Windows.Win32.System.Threading.DEBUG_ONLY_THIS_PROCESS Windows.Win32.System.Threading.DEBUG_PROCESS +Windows.Win32.System.Threading.DeleteProcThreadAttributeList Windows.Win32.System.Threading.DETACHED_PROCESS Windows.Win32.System.Threading.ExitProcess Windows.Win32.System.Threading.EXTENDED_STARTUPINFO_PRESENT @@ -2524,8 +2525,10 @@ Windows.Win32.System.Threading.INFINITE Windows.Win32.System.Threading.INHERIT_CALLER_PRIORITY Windows.Win32.System.Threading.INHERIT_PARENT_AFFINITY Windows.Win32.System.Threading.INIT_ONCE_INIT_FAILED +Windows.Win32.System.Threading.InitializeProcThreadAttributeList Windows.Win32.System.Threading.InitOnceBeginInitialize Windows.Win32.System.Threading.InitOnceComplete +Windows.Win32.System.Threading.LPPROC_THREAD_ATTRIBUTE_LIST Windows.Win32.System.Threading.LPTHREAD_START_ROUTINE Windows.Win32.System.Threading.NORMAL_PRIORITY_CLASS Windows.Win32.System.Threading.OpenProcessToken @@ -2561,6 +2564,7 @@ Windows.Win32.System.Threading.STARTF_USEPOSITION Windows.Win32.System.Threading.STARTF_USESHOWWINDOW Windows.Win32.System.Threading.STARTF_USESIZE Windows.Win32.System.Threading.STARTF_USESTDHANDLES +Windows.Win32.System.Threading.STARTUPINFOEXW Windows.Win32.System.Threading.STARTUPINFOW Windows.Win32.System.Threading.STARTUPINFOW_FLAGS Windows.Win32.System.Threading.SwitchToThread @@ -2575,6 +2579,7 @@ Windows.Win32.System.Threading.TlsGetValue Windows.Win32.System.Threading.TlsSetValue Windows.Win32.System.Threading.TryAcquireSRWLockExclusive Windows.Win32.System.Threading.TryAcquireSRWLockShared +Windows.Win32.System.Threading.UpdateProcThreadAttribute Windows.Win32.System.Threading.WaitForMultipleObjects Windows.Win32.System.Threading.WaitForSingleObject Windows.Win32.System.Threading.WakeAllConditionVariable diff --git a/library/std/src/sys/windows/c/windows_sys.rs b/library/std/src/sys/windows/c/windows_sys.rs index 02377087173..b24f6dc900f 100644 --- a/library/std/src/sys/windows/c/windows_sys.rs +++ b/library/std/src/sys/windows/c/windows_sys.rs @@ -156,6 +156,10 @@ extern "system" { } #[link(name = "kernel32")] extern "system" { + pub fn DeleteProcThreadAttributeList(lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST) -> (); +} +#[link(name = "kernel32")] +extern "system" { pub fn DeviceIoControl( hdevice: HANDLE, dwiocontrolcode: u32, @@ -372,6 +376,15 @@ extern "system" { } #[link(name = "kernel32")] extern "system" { + pub fn InitializeProcThreadAttributeList( + lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST, + dwattributecount: u32, + dwflags: u32, + lpsize: *mut usize, + ) -> BOOL; +} +#[link(name = "kernel32")] +extern "system" { pub fn MoveFileExW( lpexistingfilename: PCWSTR, lpnewfilename: PCWSTR, @@ -544,6 +557,18 @@ extern "system" { } #[link(name = "kernel32")] extern "system" { + pub fn UpdateProcThreadAttribute( + lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST, + dwflags: u32, + attribute: usize, + lpvalue: *const ::core::ffi::c_void, + cbsize: usize, + lppreviousvalue: *mut ::core::ffi::c_void, + lpreturnsize: *const usize, + ) -> BOOL; +} +#[link(name = "kernel32")] +extern "system" { pub fn WaitForMultipleObjects( ncount: u32, lphandles: *const HANDLE, @@ -3567,6 +3592,7 @@ pub type LPOVERLAPPED_COMPLETION_ROUTINE = ::core::option::Option< lpoverlapped: *mut OVERLAPPED, ) -> (), >; +pub type LPPROC_THREAD_ATTRIBUTE_LIST = *mut ::core::ffi::c_void; pub type LPPROGRESS_ROUTINE = ::core::option::Option< unsafe extern "system" fn( totalfilesize: i64, @@ -3833,6 +3859,17 @@ pub const STARTF_USESHOWWINDOW: STARTUPINFOW_FLAGS = 1u32; pub const STARTF_USESIZE: STARTUPINFOW_FLAGS = 2u32; pub const STARTF_USESTDHANDLES: STARTUPINFOW_FLAGS = 256u32; #[repr(C)] +pub struct STARTUPINFOEXW { + pub StartupInfo: STARTUPINFOW, + pub lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST, +} +impl ::core::marker::Copy for STARTUPINFOEXW {} +impl ::core::clone::Clone for STARTUPINFOEXW { + fn clone(&self) -> Self { + *self + } +} +#[repr(C)] pub struct STARTUPINFOW { pub cb: u32, pub lpReserved: PWSTR, diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 2dd0c67acdb..92edd2f6112 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -11,6 +11,7 @@ use crate::ffi::{OsStr, OsString}; use crate::fmt; use crate::io::{self, Error, ErrorKind}; use crate::mem; +use crate::mem::MaybeUninit; use crate::num::NonZeroI32; use crate::os::windows::ffi::{OsStrExt, OsStringExt}; use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle}; @@ -166,6 +167,7 @@ pub struct Command { stdout: Option<Stdio>, stderr: Option<Stdio>, force_quotes_enabled: bool, + proc_thread_attributes: BTreeMap<usize, ProcThreadAttributeValue>, } pub enum Stdio { @@ -195,6 +197,7 @@ impl Command { stdout: None, stderr: None, force_quotes_enabled: false, + proc_thread_attributes: Default::default(), } } @@ -245,6 +248,17 @@ impl Command { self.cwd.as_ref().map(|cwd| Path::new(cwd)) } + pub unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>( + &mut self, + attribute: usize, + value: T, + ) { + self.proc_thread_attributes.insert( + attribute, + ProcThreadAttributeValue { size: mem::size_of::<T>(), data: Box::new(value) }, + ); + } + pub fn spawn( &mut self, default: Stdio, @@ -308,7 +322,6 @@ impl Command { let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?; let mut si = zeroed_startupinfo(); - si.cb = mem::size_of::<c::STARTUPINFOW>() as c::DWORD; // If at least one of stdin, stdout or stderr are set (i.e. are non null) // then set the `hStd` fields in `STARTUPINFO`. @@ -322,6 +335,27 @@ impl Command { si.hStdError = stderr.as_raw_handle(); } + let si_ptr: *mut c::STARTUPINFOW; + + let mut proc_thread_attribute_list; + let mut si_ex; + + if !self.proc_thread_attributes.is_empty() { + si.cb = mem::size_of::<c::STARTUPINFOEXW>() as u32; + flags |= c::EXTENDED_STARTUPINFO_PRESENT; + + proc_thread_attribute_list = + make_proc_thread_attribute_list(&self.proc_thread_attributes)?; + si_ex = c::STARTUPINFOEXW { + StartupInfo: si, + lpAttributeList: proc_thread_attribute_list.0.as_mut_ptr() as _, + }; + si_ptr = &mut si_ex as *mut _ as _; + } else { + si.cb = mem::size_of::<c::STARTUPINFOW> as c::DWORD; + si_ptr = &mut si as *mut _ as _; + } + unsafe { cvt(c::CreateProcessW( program.as_ptr(), @@ -332,7 +366,7 @@ impl Command { flags, envp, dirp, - &si, + si_ptr, &mut pi, )) }?; @@ -831,6 +865,80 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> { } } +struct ProcThreadAttributeList(Box<[MaybeUninit<u8>]>); + +impl Drop for ProcThreadAttributeList { + fn drop(&mut self) { + let lp_attribute_list = self.0.as_mut_ptr() as _; + unsafe { c::DeleteProcThreadAttributeList(lp_attribute_list) } + } +} + +/// Wrapper around the value data to be used as a Process Thread Attribute. +struct ProcThreadAttributeValue { + data: Box<dyn Send + Sync>, + size: usize, +} + +fn make_proc_thread_attribute_list( + attributes: &BTreeMap<usize, ProcThreadAttributeValue>, +) -> io::Result<ProcThreadAttributeList> { + // To initialize our ProcThreadAttributeList, we need to determine + // how many bytes to allocate for it. The Windows API simplifies this process + // by allowing us to call `InitializeProcThreadAttributeList` with + // a null pointer to retrieve the required size. + let mut required_size = 0; + let Ok(attribute_count) = attributes.len().try_into() else { + return Err(io::const_io_error!( + ErrorKind::InvalidInput, + "maximum number of ProcThreadAttributes exceeded", + )); + }; + unsafe { + c::InitializeProcThreadAttributeList( + ptr::null_mut(), + attribute_count, + 0, + &mut required_size, + ) + }; + + let mut proc_thread_attribute_list = ProcThreadAttributeList( + vec![MaybeUninit::uninit(); required_size as usize].into_boxed_slice(), + ); + + // Once we've allocated the necessary memory, it's safe to invoke + // `InitializeProcThreadAttributeList` to properly initialize the list. + cvt(unsafe { + c::InitializeProcThreadAttributeList( + proc_thread_attribute_list.0.as_mut_ptr() as *mut _, + attribute_count, + 0, + &mut required_size, + ) + })?; + + // # Add our attributes to the buffer. + // 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 = &*value.data as *const (dyn Send + Sync) 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(), + ) + })?; + } + + Ok(proc_thread_attribute_list) +} + pub struct CommandArgs<'a> { iter: crate::slice::Iter<'a, Arg>, } diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 00e2857a137..c638cc61856 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -176,6 +176,14 @@ pub struct Instant(time::Instant); /// The size of a `SystemTime` struct may vary depending on the target operating /// system. /// +/// A `SystemTime` does not count leap seconds. +/// `SystemTime::now()`'s behaviour around a leap second +/// is the same as the operating system's wall clock. +/// The precise behaviour near a leap second +/// (e.g. whether the clock appears to run slow or fast, or stop, or jump) +/// depends on platform and configuration, +/// so should not be relied on. +/// /// Example: /// /// ```no_run @@ -461,6 +469,9 @@ impl fmt::Debug for Instant { impl SystemTime { /// An anchor in time which can be used to create new `SystemTime` instances or /// learn about where in time a `SystemTime` lies. + // + // NOTE! this documentation is duplicated, here and in std::time::UNIX_EPOCH. + // The two copies are not quite identical, because of the difference in naming. /// /// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with /// respect to the system clock. Using `duration_since` on an existing @@ -468,6 +479,11 @@ impl SystemTime { /// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a /// `SystemTime` instance to represent another fixed point in time. /// + /// `duration_since(UNIX_EPOCH).unwrap().as_secs()` returns + /// the number of non-leap seconds since the start of 1970 UTC. + /// This is a POSIX `time_t` (as a `u64`), + /// and is the same time representation as used in many Internet protocols. + /// /// # Examples /// /// ```no_run @@ -617,6 +633,9 @@ impl fmt::Debug for SystemTime { /// An anchor in time which can be used to create new `SystemTime` instances or /// learn about where in time a `SystemTime` lies. +// +// NOTE! this documentation is duplicated, here and in SystemTime::UNIX_EPOCH. +// The two copies are not quite identical, because of the difference in naming. /// /// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with /// respect to the system clock. Using `duration_since` on an existing @@ -624,6 +643,11 @@ impl fmt::Debug for SystemTime { /// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a /// [`SystemTime`] instance to represent another fixed point in time. /// +/// `duration_since(UNIX_EPOCH).unwrap().as_secs()` returns +/// the number of non-leap seconds since the start of 1970 UTC. +/// This is a POSIX `time_t` (as a `u64`), +/// and is the same time representation as used in many Internet protocols. +/// /// # Examples /// /// ```no_run |
