about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/os/fortanix_sgx/mod.rs1
-rw-r--r--library/std/src/sys/sgx/abi/usercalls/alloc.rs2
-rw-r--r--library/std/src/sys/sgx/abi/usercalls/mod.rs8
-rw-r--r--library/std/src/sys/sgx/abi/usercalls/raw.rs24
-rw-r--r--library/std/src/sys/unix/os_str.rs40
-rw-r--r--library/std/src/sys/unix/os_str/tests.rs8
-rw-r--r--library/std/src/sys/windows/c.rs26
-rw-r--r--library/std/src/sys/windows/compat.rs121
-rw-r--r--library/std/src/sys/windows/thread_parker.rs27
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);