diff options
Diffstat (limited to 'library/std/src')
| -rw-r--r-- | library/std/src/lib.rs | 1 | ||||
| -rw-r--r-- | library/std/src/os/fortanix_sgx/mod.rs | 1 | ||||
| -rw-r--r-- | library/std/src/sys/sgx/abi/usercalls/alloc.rs | 2 | ||||
| -rw-r--r-- | library/std/src/sys/sgx/abi/usercalls/mod.rs | 8 | ||||
| -rw-r--r-- | library/std/src/sys/sgx/abi/usercalls/raw.rs | 24 | ||||
| -rw-r--r-- | library/std/src/sys/unix/os_str.rs | 40 | ||||
| -rw-r--r-- | library/std/src/sys/unix/os_str/tests.rs | 8 | ||||
| -rw-r--r-- | library/std/src/sys/windows/c.rs | 26 | ||||
| -rw-r--r-- | library/std/src/sys/windows/compat.rs | 121 | ||||
| -rw-r--r-- | library/std/src/sys/windows/thread_parker.rs | 27 |
10 files changed, 156 insertions, 102 deletions
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index a8d6645794a..8627be85422 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -258,6 +258,7 @@ #![feature(staged_api)] #![feature(thread_local)] #![feature(try_blocks)] +#![feature(utf8_chunks)] // // Library features (core): #![feature(array_error_internals)] diff --git a/library/std/src/os/fortanix_sgx/mod.rs b/library/std/src/os/fortanix_sgx/mod.rs index a40dabe190a..da100b689db 100644 --- a/library/std/src/os/fortanix_sgx/mod.rs +++ b/library/std/src/os/fortanix_sgx/mod.rs @@ -26,6 +26,7 @@ pub mod usercalls { free, insecure_time, launch_thread, read, read_alloc, send, wait, write, }; pub use crate::sys::abi::usercalls::raw::{do_usercall, Usercalls as UsercallNrs}; + pub use crate::sys::abi::usercalls::raw::{Register, RegisterArgument, ReturnValue}; // fortanix-sgx-abi re-exports pub use crate::sys::abi::usercalls::raw::Error; diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index 34634da44de..fe8392f78cd 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -56,6 +56,8 @@ unsafe impl UserSafeSized for Usercall {} #[unstable(feature = "sgx_platform", issue = "56975")] unsafe impl UserSafeSized for Return {} #[unstable(feature = "sgx_platform", issue = "56975")] +unsafe impl UserSafeSized for Cancel {} +#[unstable(feature = "sgx_platform", issue = "56975")] unsafe impl<T: UserSafeSized> UserSafeSized for [T; 2] {} /// A type that can be represented in memory as one or more `UserSafeSized`s. diff --git a/library/std/src/sys/sgx/abi/usercalls/mod.rs b/library/std/src/sys/sgx/abi/usercalls/mod.rs index 79d1db5e1c5..e19e843267a 100644 --- a/library/std/src/sys/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/sgx/abi/usercalls/mod.rs @@ -292,12 +292,17 @@ fn check_os_error(err: Result) -> i32 { } } -trait FromSgxResult { +/// Translate the raw result of an SGX usercall. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub trait FromSgxResult { + /// Return type type Return; + /// Translate the raw result of an SGX usercall. fn from_sgx_result(self) -> IoResult<Self::Return>; } +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T> FromSgxResult for (Result, T) { type Return = T; @@ -310,6 +315,7 @@ impl<T> FromSgxResult for (Result, T) { } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl FromSgxResult for Result { type Return = (); diff --git a/library/std/src/sys/sgx/abi/usercalls/raw.rs b/library/std/src/sys/sgx/abi/usercalls/raw.rs index 4267b96ccd5..10c1456d4fd 100644 --- a/library/std/src/sys/sgx/abi/usercalls/raw.rs +++ b/library/std/src/sys/sgx/abi/usercalls/raw.rs @@ -37,14 +37,23 @@ pub unsafe fn do_usercall( (a, b) } -type Register = u64; +/// A value passed or returned in a CPU register. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub type Register = u64; -trait RegisterArgument { +/// Translate a type from/to Register to be used as an argument. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub trait RegisterArgument { + /// Translate a Register to Self. fn from_register(_: Register) -> Self; + /// Translate self to a Register. fn into_register(self) -> Register; } -trait ReturnValue { +/// Translate a pair of Registers to the raw usercall return value. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub trait ReturnValue { + /// Translate a pair of Registers to the raw usercall return value. fn from_registers(call: &'static str, regs: (Register, Register)) -> Self; } @@ -68,6 +77,7 @@ macro_rules! define_usercalls { macro_rules! define_ra { (< $i:ident > $t:ty) => { + #[unstable(feature = "sgx_platform", issue = "56975")] impl<$i> RegisterArgument for $t { fn from_register(a: Register) -> Self { a as _ @@ -78,6 +88,7 @@ macro_rules! define_ra { } }; ($i:ty as $t:ty) => { + #[unstable(feature = "sgx_platform", issue = "56975")] impl RegisterArgument for $t { fn from_register(a: Register) -> Self { a as $i as _ @@ -88,6 +99,7 @@ macro_rules! define_ra { } }; ($t:ty) => { + #[unstable(feature = "sgx_platform", issue = "56975")] impl RegisterArgument for $t { fn from_register(a: Register) -> Self { a as _ @@ -112,6 +124,7 @@ define_ra!(usize as isize); define_ra!(<T> *const T); define_ra!(<T> *mut T); +#[unstable(feature = "sgx_platform", issue = "56975")] impl RegisterArgument for bool { fn from_register(a: Register) -> bool { if a != 0 { true } else { false } @@ -121,6 +134,7 @@ impl RegisterArgument for bool { } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T: RegisterArgument> RegisterArgument for Option<NonNull<T>> { fn from_register(a: Register) -> Option<NonNull<T>> { NonNull::new(a as _) @@ -130,12 +144,14 @@ impl<T: RegisterArgument> RegisterArgument for Option<NonNull<T>> { } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl ReturnValue for ! { fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self { rtabort!("Usercall {call}: did not expect to be re-entered"); } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl ReturnValue for () { fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self { rtassert!(usercall_retval.0 == 0); @@ -144,6 +160,7 @@ impl ReturnValue for () { } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T: RegisterArgument> ReturnValue for T { fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self { rtassert!(usercall_retval.1 == 0); @@ -151,6 +168,7 @@ impl<T: RegisterArgument> ReturnValue for T { } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T: RegisterArgument, U: RegisterArgument> ReturnValue for (T, U) { fn from_registers(_call: &'static str, regs: (Register, Register)) -> Self { (T::from_register(regs.0), U::from_register(regs.1)) diff --git a/library/std/src/sys/unix/os_str.rs b/library/std/src/sys/unix/os_str.rs index ccbc182240c..017e2af29d4 100644 --- a/library/std/src/sys/unix/os_str.rs +++ b/library/std/src/sys/unix/os_str.rs @@ -11,7 +11,7 @@ use crate::str; use crate::sync::Arc; use crate::sys_common::{AsInner, IntoInner}; -use core::str::lossy::{Utf8Lossy, Utf8LossyChunk}; +use core::str::Utf8Chunks; #[cfg(test)] #[path = "../unix/os_str/tests.rs"] @@ -29,26 +29,32 @@ pub struct Slice { } impl fmt::Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - // Writes out a valid unicode string with the correct escape sequences - - formatter.write_str("\"")?; - for Utf8LossyChunk { valid, broken } in Utf8Lossy::from_bytes(&self.inner).chunks() { - for c in valid.chars().flat_map(|c| c.escape_debug()) { - formatter.write_char(c)? - } - - for b in broken { - write!(formatter, "\\x{:02X}", b)?; - } - } - formatter.write_str("\"") + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&Utf8Chunks::new(&self.inner).debug(), f) } } impl fmt::Display for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // If we're the empty string then our iterator won't actually yield + // anything, so perform the formatting manually + if self.inner.is_empty() { + return "".fmt(f); + } + + for chunk in Utf8Chunks::new(&self.inner) { + let valid = chunk.valid(); + // If we successfully decoded the whole chunk as a valid string then + // we can return a direct formatting of the string which will also + // respect various formatting flags if possible. + if chunk.invalid().is_empty() { + return valid.fmt(f); + } + + f.write_str(valid)?; + f.write_char(char::REPLACEMENT_CHARACTER)?; + } + Ok(()) } } diff --git a/library/std/src/sys/unix/os_str/tests.rs b/library/std/src/sys/unix/os_str/tests.rs index 213277f01f2..22ba0c92350 100644 --- a/library/std/src/sys/unix/os_str/tests.rs +++ b/library/std/src/sys/unix/os_str/tests.rs @@ -8,3 +8,11 @@ fn slice_debug_output() { assert_eq!(output, expected); } + +#[test] +fn display() { + assert_eq!( + "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", + Slice::from_u8_slice(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string(), + ); +} diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index c5a30f8bac8..ef3f6a9ba17 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -228,6 +228,8 @@ pub const IPV6_ADD_MEMBERSHIP: c_int = 12; pub const IPV6_DROP_MEMBERSHIP: c_int = 13; pub const MSG_PEEK: c_int = 0x2; +pub const LOAD_LIBRARY_SEARCH_SYSTEM32: u32 = 0x800; + #[repr(C)] #[derive(Copy, Clone)] pub struct linger { @@ -1030,6 +1032,7 @@ extern "system" { pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void; pub fn GetModuleHandleA(lpModuleName: LPCSTR) -> HMODULE; pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; + pub fn LoadLibraryExA(lplibfilename: *const i8, hfile: HANDLE, dwflags: u32) -> HINSTANCE; pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME); pub fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO); @@ -1250,21 +1253,16 @@ compat_fn_with_fallback! { } } -compat_fn_with_fallback! { - pub static SYNCH_API: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0"); - #[allow(unused)] - fn WakeByAddressSingle(Address: LPVOID) -> () { - // This fallback is currently tightly coupled to its use in Parker::unpark. - // - // FIXME: If `WakeByAddressSingle` needs to be used anywhere other than - // Parker::unpark then this fallback will be wrong and will need to be decoupled. - crate::sys::windows::thread_parker::unpark_keyed_event(Address) - } +compat_fn_optional! { + crate::sys::compat::load_synch_functions(); + pub fn WaitOnAddress( + Address: LPVOID, + CompareAddress: LPVOID, + AddressSize: SIZE_T, + dwMilliseconds: DWORD + ); + pub fn WakeByAddressSingle(Address: LPVOID); } -pub use crate::sys::compat::WaitOnAddress; -// Change exported name of `WakeByAddressSingle` to make the strange fallback -// behaviour clear. -pub use WakeByAddressSingle::call as wake_by_address_single_or_unpark_keyed_event; compat_fn_with_fallback! { pub static NTDLL: &CStr = ansi_str!("ntdll"); diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs index 473544c4d4f..9c8ddc3aa1d 100644 --- a/library/std/src/sys/windows/compat.rs +++ b/library/std/src/sys/windows/compat.rs @@ -21,6 +21,7 @@ use crate::ffi::{c_void, CStr}; use crate::ptr::NonNull; +use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::c; /// Helper macro for creating CStrs from literals and symbol names. @@ -74,6 +75,20 @@ impl Module { NonNull::new(module).map(Self) } + /// Load the library (if not already loaded) + /// + /// # Safety + /// + /// The module must not be unloaded. + pub unsafe fn load_system_library(name: &CStr) -> Option<Self> { + let module = c::LoadLibraryExA( + name.as_ptr(), + crate::ptr::null_mut(), + c::LOAD_LIBRARY_SEARCH_SYSTEM32, + ); + NonNull::new(module).map(Self) + } + // Try to get the address of a function. pub fn proc_address(self, name: &CStr) -> Option<NonNull<c_void>> { // SAFETY: @@ -144,61 +159,63 @@ macro_rules! compat_fn_with_fallback { )*) } -/// Optionally load `WaitOnAddress`. -/// Unlike the dynamic loading described above, this does not have a fallback. +/// Optionally loaded functions. /// -/// This is rexported from sys::c. You should prefer to import -/// from there in case this changes again in the future. -pub mod WaitOnAddress { - use super::*; - use crate::mem; - use crate::ptr; - use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering}; - use crate::sys::c; - - static MODULE_NAME: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0"); - static SYMBOL_NAME: &CStr = ansi_str!("WaitOnAddress"); - - // WaitOnAddress function signature. - type F = unsafe extern "system" fn( - Address: c::LPVOID, - CompareAddress: c::LPVOID, - AddressSize: c::SIZE_T, - dwMilliseconds: c::DWORD, - ); - - // A place to store the loaded function atomically. - static WAIT_ON_ADDRESS: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut()); - - // We can skip trying to load again if we already tried. - static LOAD_MODULE: AtomicBool = AtomicBool::new(true); - - #[inline(always)] - pub fn option() -> Option<F> { - let f = WAIT_ON_ADDRESS.load(Ordering::Acquire); - if !f.is_null() { Some(unsafe { mem::transmute(f) }) } else { try_load() } - } +/// Actual loading of the function defers to $load_functions. +macro_rules! compat_fn_optional { + ($load_functions:expr; + $( + $(#[$meta:meta])* + $vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),*) $(-> $rettype:ty)?; + )+) => ( + $( + pub mod $symbol { + use super::*; + use crate::ffi::c_void; + use crate::mem; + use crate::ptr::{self, NonNull}; + use crate::sync::atomic::{AtomicPtr, Ordering}; + + pub(in crate::sys) static PTR: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut()); + + type F = unsafe extern "system" fn($($argtype),*) $(-> $rettype)?; + + #[inline(always)] + pub fn option() -> Option<F> { + let f = PTR.load(Ordering::Acquire); + if !f.is_null() { Some(unsafe { mem::transmute(f) }) } else { try_load() } + } - #[cold] - fn try_load() -> Option<F> { - if LOAD_MODULE.load(Ordering::Acquire) { - // load the module - let mut wait_on_address = None; - if let Some(func) = try_load_inner() { - WAIT_ON_ADDRESS.store(func.as_ptr(), Ordering::Release); - wait_on_address = Some(unsafe { mem::transmute(func) }); + #[cold] + fn try_load() -> Option<F> { + $load_functions; + NonNull::new(PTR.load(Ordering::Acquire)).map(|f| unsafe { mem::transmute(f) }) + } } - // Don't try to load the module again even if loading failed. - LOAD_MODULE.store(false, Ordering::Release); - wait_on_address - } else { - None - } - } + )+ + ) +} - // In the future this could be a `try` block but until then I think it's a - // little bit cleaner as a separate function. - fn try_load_inner() -> Option<NonNull<c_void>> { - unsafe { Module::new(MODULE_NAME)?.proc_address(SYMBOL_NAME) } +/// Load all needed functions from "api-ms-win-core-synch-l1-2-0". +pub(super) fn load_synch_functions() { + fn try_load() -> Option<()> { + const MODULE_NAME: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0"); + const WAIT_ON_ADDRESS: &CStr = ansi_str!("WaitOnAddress"); + const WAKE_BY_ADDRESS_SINGLE: &CStr = ansi_str!("WakeByAddressSingle"); + + // Try loading the library and all the required functions. + // If any step fails, then they all fail. + let library = unsafe { Module::load_system_library(MODULE_NAME) }?; + let wait_on_address = library.proc_address(WAIT_ON_ADDRESS)?; + let wake_by_address_single = library.proc_address(WAKE_BY_ADDRESS_SINGLE)?; + + c::WaitOnAddress::PTR.store(wait_on_address.as_ptr(), Ordering::Release); + c::WakeByAddressSingle::PTR.store(wake_by_address_single.as_ptr(), Ordering::Release); + Some(()) } + + // Try to load the module but skip loading if a previous attempt failed. + static LOAD_MODULE: AtomicBool = AtomicBool::new(true); + let module_loaded = LOAD_MODULE.load(Ordering::Acquire) && try_load().is_some(); + LOAD_MODULE.store(module_loaded, Ordering::Release) } diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs index 16863c9903a..2f7ae863b6a 100644 --- a/library/std/src/sys/windows/thread_parker.rs +++ b/library/std/src/sys/windows/thread_parker.rs @@ -198,8 +198,18 @@ impl Parker { // with park(). if self.state.swap(NOTIFIED, Release) == PARKED { unsafe { - // This calls either WakeByAddressSingle or unpark_keyed_event (see below). - c::wake_by_address_single_or_unpark_keyed_event(self.ptr()); + if let Some(wake_by_address_single) = c::WakeByAddressSingle::option() { + wake_by_address_single(self.ptr()); + } else { + // If we run NtReleaseKeyedEvent before the waiting thread runs + // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up. + // If the waiting thread wakes up before we run NtReleaseKeyedEvent + // (e.g. due to a timeout), this blocks until we do wake up a thread. + // To prevent this thread from blocking indefinitely in that case, + // park_impl() will, after seeing the state set to NOTIFIED after + // waking up, call NtWaitForKeyedEvent again to unblock us. + c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut()); + } } } } @@ -209,19 +219,6 @@ impl Parker { } } -// This function signature makes it compatible with c::WakeByAddressSingle -// so that it can be used as a fallback for that function. -pub unsafe extern "C" fn unpark_keyed_event(address: c::LPVOID) { - // If we run NtReleaseKeyedEvent before the waiting thread runs - // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up. - // If the waiting thread wakes up before we run NtReleaseKeyedEvent - // (e.g. due to a timeout), this blocks until we do wake up a thread. - // To prevent this thread from blocking indefinitely in that case, - // park_impl() will, after seeing the state set to NOTIFIED after - // waking up, call NtWaitForKeyedEvent again to unblock us. - c::NtReleaseKeyedEvent(keyed_event_handle(), address, 0, ptr::null_mut()); -} - fn keyed_event_handle() -> c::HANDLE { const INVALID: c::HANDLE = ptr::invalid_mut(!0); static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID); |
