summaryrefslogtreecommitdiffstats
path: root/library/std
diff options
context:
space:
mode:
Diffstat (limited to 'library/std')
-rw-r--r--library/std/Cargo.toml5
-rw-r--r--library/std/build.rs2
-rw-r--r--library/std/src/backtrace.rs4
-rw-r--r--library/std/src/backtrace/tests.rs2
-rw-r--r--library/std/src/collections/hash/map.rs157
-rw-r--r--library/std/src/collections/hash/map/tests.rs2
-rw-r--r--library/std/src/collections/hash/set.rs10
-rw-r--r--library/std/src/collections/hash/set/tests.rs2
-rw-r--r--library/std/src/collections/mod.rs5
-rw-r--r--library/std/src/env.rs50
-rw-r--r--library/std/src/env/tests.rs2
-rw-r--r--library/std/src/error.rs8
-rw-r--r--library/std/src/ffi/os_str.rs82
-rw-r--r--library/std/src/ffi/os_str/tests.rs54
-rw-r--r--library/std/src/fs/tests.rs29
-rw-r--r--library/std/src/hash/mod.rs91
-rw-r--r--library/std/src/hash/random.rs161
-rw-r--r--library/std/src/io/buffered/bufreader.rs10
-rw-r--r--library/std/src/io/copy.rs69
-rw-r--r--library/std/src/io/copy/tests.rs11
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs1
-rw-r--r--library/std/src/io/error/repr_unpacked.rs1
-rw-r--r--library/std/src/io/mod.rs236
-rw-r--r--library/std/src/io/tests.rs30
-rw-r--r--library/std/src/lib.rs13
-rw-r--r--library/std/src/macros.rs6
-rw-r--r--library/std/src/net/tcp/tests.rs2
-rw-r--r--library/std/src/net/udp/tests.rs1
-rw-r--r--library/std/src/os/l4re/raw.rs1
-rw-r--r--library/std/src/os/linux/process.rs6
-rw-r--r--library/std/src/os/linux/raw.rs1
-rw-r--r--library/std/src/os/solid/io.rs300
-rw-r--r--library/std/src/os/solid/mod.rs2
-rw-r--r--library/std/src/os/windows/io/handle.rs2
-rw-r--r--library/std/src/os/windows/io/socket.rs4
-rw-r--r--library/std/src/os/windows/process.rs6
-rw-r--r--library/std/src/panicking.rs4
-rw-r--r--library/std/src/path/tests.rs8
-rw-r--r--library/std/src/process.rs4
-rw-r--r--library/std/src/rt.rs3
-rw-r--r--library/std/src/sync/mpsc/sync_tests.rs1
-rw-r--r--library/std/src/sync/mpsc/tests.rs1
-rw-r--r--library/std/src/sync/mutex.rs2
-rw-r--r--library/std/src/sync/once_lock.rs61
-rw-r--r--library/std/src/sync/rwlock.rs4
-rw-r--r--library/std/src/sys/common/alloc.rs1
-rw-r--r--library/std/src/sys/mod.rs3
-rw-r--r--library/std/src/sys/personality/mod.rs3
-rw-r--r--library/std/src/sys/solid/net.rs201
-rw-r--r--library/std/src/sys/teeos/alloc.rs57
-rw-r--r--library/std/src/sys/teeos/locks/condvar.rs100
-rw-r--r--library/std/src/sys/teeos/locks/mod.rs8
-rw-r--r--library/std/src/sys/teeos/locks/rwlock.rs44
-rw-r--r--library/std/src/sys/teeos/mod.rs167
-rw-r--r--library/std/src/sys/teeos/net.rs372
-rw-r--r--library/std/src/sys/teeos/os.rs134
-rw-r--r--library/std/src/sys/teeos/rand.rs21
-rw-r--r--library/std/src/sys/teeos/stdio.rs88
-rw-r--r--library/std/src/sys/teeos/thread.rs164
-rw-r--r--library/std/src/sys/teeos/thread_local_dtor.rs4
-rw-r--r--library/std/src/sys/unix/args.rs16
-rw-r--r--library/std/src/sys/unix/env.rs11
-rw-r--r--library/std/src/sys/unix/fs.rs20
-rw-r--r--library/std/src/sys/unix/mod.rs7
-rw-r--r--library/std/src/sys/unix/os.rs12
-rw-r--r--library/std/src/sys/unix/process/process_common.rs9
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs76
-rw-r--r--library/std/src/sys/unix/process/process_unix/tests.rs19
-rw-r--r--library/std/src/sys/unix/thread.rs3
-rw-r--r--library/std/src/sys/unix/thread_local_dtor.rs10
-rw-r--r--library/std/src/sys/unix/time.rs12
-rw-r--r--library/std/src/sys/wasi/fs.rs13
-rw-r--r--library/std/src/sys/windows/api.rs4
-rw-r--r--library/std/src/sys/windows/c.rs9
-rw-r--r--library/std/src/sys/windows/c/windows_sys.lst4
-rw-r--r--library/std/src/sys/windows/c/windows_sys.rs9
-rw-r--r--library/std/src/sys/windows/compat.rs6
-rw-r--r--library/std/src/sys/windows/fs.rs49
-rw-r--r--library/std/src/sys/windows/handle.rs10
-rw-r--r--library/std/src/sys/windows/io.rs6
-rw-r--r--library/std/src/sys/windows/mod.rs6
-rw-r--r--library/std/src/sys/windows/net.rs2
-rw-r--r--library/std/src/sys/windows/os.rs6
-rw-r--r--library/std/src/sys/windows/path.rs16
-rw-r--r--library/std/src/sys/windows/process.rs13
-rw-r--r--library/std/src/sys/windows/stdio.rs8
-rw-r--r--library/std/src/sys/windows/time.rs4
-rw-r--r--library/std/src/sys/xous/mod.rs1
-rw-r--r--library/std/src/sys/xous/os.rs29
-rw-r--r--library/std/src/sys/xous/thread_parking.rs94
-rw-r--r--library/std/src/sys_common/backtrace.rs12
-rw-r--r--library/std/src/sys_common/mod.rs16
-rw-r--r--library/std/src/sys_common/once/futex.rs3
-rw-r--r--library/std/src/sys_common/thread.rs2
-rw-r--r--library/std/src/sys_common/wtf8/tests.rs1
-rw-r--r--library/std/src/thread/mod.rs5
-rw-r--r--library/std/tests/common/mod.rs4
97 files changed, 2723 insertions, 627 deletions
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index f666b1888..fe66788b5 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -30,8 +30,13 @@ rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] }
[target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies]
miniz_oxide = { version = "0.7.0", optional = true, default-features = false }
addr2line = { version = "0.21.0", optional = true, default-features = false }
+
+[target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies]
object = { version = "0.32.0", default-features = false, optional = true, features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] }
+[target.'cfg(target_os = "aix")'.dependencies]
+object = { version = "0.32.0", default-features = false, optional = true, features = ['read_core', 'xcoff', 'unaligned', 'archive'] }
+
[dev-dependencies]
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
rand_xorshift = "0.3.0"
diff --git a/library/std/build.rs b/library/std/build.rs
index ad0a82eab..0f5068b59 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -25,7 +25,6 @@ fn main() {
|| target.contains("vxworks")
|| target.contains("wasm32")
|| target.contains("wasm64")
- || target.contains("asmjs")
|| target.contains("espidf")
|| target.contains("solid")
|| target.contains("nintendo-3ds")
@@ -35,6 +34,7 @@ fn main() {
|| target.contains("xous")
|| target.contains("hurd")
|| target.contains("uefi")
+ || target.contains("teeos")
// See src/bootstrap/synthetic_targets.rs
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
{
diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs
index e7110aebd..9638f4919 100644
--- a/library/std/src/backtrace.rs
+++ b/library/std/src/backtrace.rs
@@ -95,8 +95,7 @@ use crate::fmt;
use crate::panic::UnwindSafe;
use crate::sync::atomic::{AtomicUsize, Ordering::Relaxed};
use crate::sync::LazyLock;
-use crate::sys_common::backtrace::{lock, output_filename};
-use crate::vec::Vec;
+use crate::sys_common::backtrace::{lock, output_filename, set_image_base};
/// A captured OS thread stack backtrace.
///
@@ -327,6 +326,7 @@ impl Backtrace {
let _lock = lock();
let mut frames = Vec::new();
let mut actual_start = None;
+ set_image_base();
unsafe {
backtrace_rs::trace_unsynchronized(|frame| {
frames.push(BacktraceFrame {
diff --git a/library/std/src/backtrace/tests.rs b/library/std/src/backtrace/tests.rs
index 73543a3af..174d62813 100644
--- a/library/std/src/backtrace/tests.rs
+++ b/library/std/src/backtrace/tests.rs
@@ -1,5 +1,5 @@
use super::*;
-use crate::panic::{RefUnwindSafe, UnwindSafe};
+use crate::panic::RefUnwindSafe;
fn generate_fake_frames() -> Vec<BacktraceFrame> {
vec![
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 4d109285d..39e94902c 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -6,16 +6,13 @@ use self::Entry::*;
use hashbrown::hash_map as base;
use crate::borrow::Borrow;
-use crate::cell::Cell;
use crate::collections::TryReserveError;
use crate::collections::TryReserveErrorKind;
use crate::error::Error;
use crate::fmt::{self, Debug};
-#[allow(deprecated)]
-use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13};
+use crate::hash::{BuildHasher, Hash, RandomState};
use crate::iter::FusedIterator;
use crate::ops::Index;
-use crate::sys;
/// A [hash map] implemented with quadratic probing and SIMD lookup.
///
@@ -274,7 +271,7 @@ impl<K, V, S> HashMap<K, V, S> {
///
/// ```
/// use std::collections::HashMap;
- /// use std::collections::hash_map::RandomState;
+ /// use std::hash::RandomState;
///
/// let s = RandomState::new();
/// let mut map = HashMap::with_hasher(s);
@@ -306,7 +303,7 @@ impl<K, V, S> HashMap<K, V, S> {
///
/// ```
/// use std::collections::HashMap;
- /// use std::collections::hash_map::RandomState;
+ /// use std::hash::RandomState;
///
/// let s = RandomState::new();
/// let mut map = HashMap::with_capacity_and_hasher(10, s);
@@ -717,7 +714,7 @@ impl<K, V, S> HashMap<K, V, S> {
///
/// ```
/// use std::collections::HashMap;
- /// use std::collections::hash_map::RandomState;
+ /// use std::hash::RandomState;
///
/// let hasher = RandomState::new();
/// let map: HashMap<i32, i32> = HashMap::with_hasher(hasher);
@@ -3072,152 +3069,6 @@ where
}
}
-/// `RandomState` is the default state for [`HashMap`] types.
-///
-/// A particular instance `RandomState` will create the same instances of
-/// [`Hasher`], but the hashers created by two different `RandomState`
-/// instances are unlikely to produce the same result for the same values.
-///
-/// # Examples
-///
-/// ```
-/// use std::collections::HashMap;
-/// use std::collections::hash_map::RandomState;
-///
-/// let s = RandomState::new();
-/// let mut map = HashMap::with_hasher(s);
-/// map.insert(1, 2);
-/// ```
-#[derive(Clone)]
-#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
-pub struct RandomState {
- k0: u64,
- k1: u64,
-}
-
-impl RandomState {
- /// Constructs a new `RandomState` that is initialized with random keys.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::collections::hash_map::RandomState;
- ///
- /// let s = RandomState::new();
- /// ```
- #[inline]
- #[allow(deprecated)]
- // rand
- #[must_use]
- #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
- pub fn new() -> RandomState {
- // Historically this function did not cache keys from the OS and instead
- // simply always called `rand::thread_rng().gen()` twice. In #31356 it
- // was discovered, however, that because we re-seed the thread-local RNG
- // from the OS periodically that this can cause excessive slowdown when
- // many hash maps are created on a thread. To solve this performance
- // trap we cache the first set of randomly generated keys per-thread.
- //
- // Later in #36481 it was discovered that exposing a deterministic
- // iteration order allows a form of DOS attack. To counter that we
- // increment one of the seeds on every RandomState creation, giving
- // every corresponding HashMap a different iteration order.
- thread_local!(static KEYS: Cell<(u64, u64)> = {
- Cell::new(sys::hashmap_random_keys())
- });
-
- KEYS.with(|keys| {
- let (k0, k1) = keys.get();
- keys.set((k0.wrapping_add(1), k1));
- RandomState { k0, k1 }
- })
- }
-}
-
-#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
-impl BuildHasher for RandomState {
- type Hasher = DefaultHasher;
- #[inline]
- #[allow(deprecated)]
- fn build_hasher(&self) -> DefaultHasher {
- DefaultHasher(SipHasher13::new_with_keys(self.k0, self.k1))
- }
-}
-
-/// The default [`Hasher`] used by [`RandomState`].
-///
-/// The internal algorithm is not specified, and so it and its hashes should
-/// not be relied upon over releases.
-#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
-#[allow(deprecated)]
-#[derive(Clone, Debug)]
-pub struct DefaultHasher(SipHasher13);
-
-impl DefaultHasher {
- /// Creates a new `DefaultHasher`.
- ///
- /// This hasher is not guaranteed to be the same as all other
- /// `DefaultHasher` instances, but is the same as all other `DefaultHasher`
- /// instances created through `new` or `default`.
- #[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
- #[inline]
- #[allow(deprecated)]
- #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
- #[must_use]
- pub const fn new() -> DefaultHasher {
- DefaultHasher(SipHasher13::new_with_keys(0, 0))
- }
-}
-
-#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
-impl Default for DefaultHasher {
- /// Creates a new `DefaultHasher` using [`new`].
- /// See its documentation for more.
- ///
- /// [`new`]: DefaultHasher::new
- #[inline]
- fn default() -> DefaultHasher {
- DefaultHasher::new()
- }
-}
-
-#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
-impl Hasher for DefaultHasher {
- // The underlying `SipHasher13` doesn't override the other
- // `write_*` methods, so it's ok not to forward them here.
-
- #[inline]
- fn write(&mut self, msg: &[u8]) {
- self.0.write(msg)
- }
-
- #[inline]
- fn write_str(&mut self, s: &str) {
- self.0.write_str(s);
- }
-
- #[inline]
- fn finish(&self) -> u64 {
- self.0.finish()
- }
-}
-
-#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
-impl Default for RandomState {
- /// Constructs a new `RandomState`.
- #[inline]
- fn default() -> RandomState {
- RandomState::new()
- }
-}
-
-#[stable(feature = "std_debug", since = "1.16.0")]
-impl fmt::Debug for RandomState {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("RandomState").finish_non_exhaustive()
- }
-}
-
#[inline]
fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, V> {
match raw {
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index 91a3776e7..8585376ab 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -1,8 +1,8 @@
use super::Entry::{Occupied, Vacant};
use super::HashMap;
-use super::RandomState;
use crate::assert_matches::assert_matches;
use crate::cell::RefCell;
+use crate::hash::RandomState;
use crate::test_helpers::test_rng;
use rand::Rng;
use realstd::collections::TryReserveErrorKind::*;
diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs
index 6a87f6e5f..8bc596082 100644
--- a/library/std/src/collections/hash/set.rs
+++ b/library/std/src/collections/hash/set.rs
@@ -6,11 +6,11 @@ use hashbrown::hash_set as base;
use crate::borrow::Borrow;
use crate::collections::TryReserveError;
use crate::fmt;
-use crate::hash::{BuildHasher, Hash};
+use crate::hash::{BuildHasher, Hash, RandomState};
use crate::iter::{Chain, FusedIterator};
use crate::ops::{BitAnd, BitOr, BitXor, Sub};
-use super::map::{map_try_reserve_error, RandomState};
+use super::map::map_try_reserve_error;
/// A [hash set] implemented as a `HashMap` where the value is `()`.
///
@@ -361,7 +361,7 @@ impl<T, S> HashSet<T, S> {
///
/// ```
/// use std::collections::HashSet;
- /// use std::collections::hash_map::RandomState;
+ /// use std::hash::RandomState;
///
/// let s = RandomState::new();
/// let mut set = HashSet::with_hasher(s);
@@ -393,7 +393,7 @@ impl<T, S> HashSet<T, S> {
///
/// ```
/// use std::collections::HashSet;
- /// use std::collections::hash_map::RandomState;
+ /// use std::hash::RandomState;
///
/// let s = RandomState::new();
/// let mut set = HashSet::with_capacity_and_hasher(10, s);
@@ -411,7 +411,7 @@ impl<T, S> HashSet<T, S> {
///
/// ```
/// use std::collections::HashSet;
- /// use std::collections::hash_map::RandomState;
+ /// use std::hash::RandomState;
///
/// let hasher = RandomState::new();
/// let set: HashSet<i32> = HashSet::with_hasher(hasher);
diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs
index e0cd80b44..208f61e75 100644
--- a/library/std/src/collections/hash/set/tests.rs
+++ b/library/std/src/collections/hash/set/tests.rs
@@ -1,6 +1,6 @@
-use super::super::map::RandomState;
use super::HashSet;
+use crate::hash::RandomState;
use crate::panic::{catch_unwind, AssertUnwindSafe};
use crate::sync::atomic::{AtomicU32, Ordering};
use crate::sync::Arc;
diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs
index 42f738acb..1389d24a8 100644
--- a/library/std/src/collections/mod.rs
+++ b/library/std/src/collections/mod.rs
@@ -439,6 +439,11 @@ pub mod hash_map {
//! A hash map implemented with quadratic probing and SIMD lookup.
#[stable(feature = "rust1", since = "1.0.0")]
pub use super::hash::map::*;
+
+ #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+ pub use crate::hash::random::DefaultHasher;
+ #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+ pub use crate::hash::random::RandomState;
}
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index f67f6034d..30ac05123 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -313,17 +313,32 @@ impl Error for VarError {
/// Sets the environment variable `key` to the value `value` for the currently running
/// process.
///
-/// Note that while concurrent access to environment variables is safe in Rust,
-/// some platforms only expose inherently unsafe non-threadsafe APIs for
-/// inspecting the environment. As a result, extra care needs to be taken when
-/// auditing calls to unsafe external FFI functions to ensure that any external
-/// environment accesses are properly synchronized with accesses in Rust.
+/// # Safety
+///
+/// Even though this function is currently not marked as `unsafe`, it needs to
+/// be because invoking it can cause undefined behaviour. The function will be
+/// marked `unsafe` in a future version of Rust. This is tracked in
+/// [rust#27970](https://github.com/rust-lang/rust/issues/27970).
+///
+/// This function is safe to call in a single-threaded program.
+///
+/// In multi-threaded programs, you must ensure that are no other threads
+/// concurrently writing or *reading*(!) from the environment through functions
+/// other than the ones in this module. You are responsible for figuring out
+/// how to achieve this, but we strongly suggest not using `set_var` or
+/// `remove_var` in multi-threaded programs at all.
+///
+/// Most C libraries, including libc itself do not advertise which functions
+/// read from the environment. Even functions from the Rust standard library do
+/// that, e.g. for DNS lookups from [`std::net::ToSocketAddrs`].
///
/// Discussion of this unsafety on Unix may be found in:
///
/// - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188)
/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
///
+/// [`std::net::ToSocketAddrs`]: crate::net::ToSocketAddrs
+///
/// # Panics
///
/// This function may panic if `key` is empty, contains an ASCII equals sign `'='`
@@ -351,17 +366,32 @@ fn _set_var(key: &OsStr, value: &OsStr) {
/// Removes an environment variable from the environment of the currently running process.
///
-/// Note that while concurrent access to environment variables is safe in Rust,
-/// some platforms only expose inherently unsafe non-threadsafe APIs for
-/// inspecting the environment. As a result extra care needs to be taken when
-/// auditing calls to unsafe external FFI functions to ensure that any external
-/// environment accesses are properly synchronized with accesses in Rust.
+/// # Safety
+///
+/// Even though this function is currently not marked as `unsafe`, it needs to
+/// be because invoking it can cause undefined behaviour. The function will be
+/// marked `unsafe` in a future version of Rust. This is tracked in
+/// [rust#27970](https://github.com/rust-lang/rust/issues/27970).
+///
+/// This function is safe to call in a single-threaded program.
+///
+/// In multi-threaded programs, you must ensure that are no other threads
+/// concurrently writing or *reading*(!) from the environment through functions
+/// other than the ones in this module. You are responsible for figuring out
+/// how to achieve this, but we strongly suggest not using `set_var` or
+/// `remove_var` in multi-threaded programs at all.
+///
+/// Most C libraries, including libc itself do not advertise which functions
+/// read from the environment. Even functions from the Rust standard library do
+/// that, e.g. for DNS lookups from [`std::net::ToSocketAddrs`].
///
/// Discussion of this unsafety on Unix may be found in:
///
/// - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188)
/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
///
+/// [`std::net::ToSocketAddrs`]: crate::net::ToSocketAddrs
+///
/// # Panics
///
/// This function may panic if `key` is empty, contains an ASCII equals sign
diff --git a/library/std/src/env/tests.rs b/library/std/src/env/tests.rs
index 558692295..fc7aee297 100644
--- a/library/std/src/env/tests.rs
+++ b/library/std/src/env/tests.rs
@@ -1,7 +1,5 @@
use super::*;
-use crate::path::Path;
-
#[test]
#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
fn test_self_exe_path() {
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index 375ff2d24..b240e4e2c 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -12,14 +12,6 @@ pub use core::error::Error;
#[unstable(feature = "error_generic_member_access", issue = "99301")]
pub use core::error::{request_ref, request_value, Request};
-mod private {
- // This is a hack to prevent `type_id` from being overridden by `Error`
- // implementations, since that can enable unsound downcasting.
- #[unstable(feature = "error_type_id", issue = "60784")]
- #[derive(Debug)]
- pub struct Internal;
-}
-
/// An error reporter that prints an error and its sources.
///
/// Report also exposes configuration options for formatting the error sources, either entirely on a
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index fa9d48771..819731821 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -6,9 +6,10 @@ use crate::cmp;
use crate::collections::TryReserveError;
use crate::fmt;
use crate::hash::{Hash, Hasher};
-use crate::ops;
+use crate::ops::{self, Range};
use crate::rc::Rc;
-use crate::str::FromStr;
+use crate::slice;
+use crate::str::{from_utf8 as str_from_utf8, FromStr};
use crate::sync::Arc;
use crate::sys::os_str::{Buf, Slice};
@@ -963,6 +964,83 @@ impl OsStr {
self.inner.as_encoded_bytes()
}
+ /// Takes a substring based on a range that corresponds to the return value of
+ /// [`OsStr::as_encoded_bytes`].
+ ///
+ /// The range's start and end must lie on valid `OsStr` boundaries.
+ /// A valid `OsStr` boundary is one of:
+ /// - The start of the string
+ /// - The end of the string
+ /// - Immediately before a valid non-empty UTF-8 substring
+ /// - Immediately after a valid non-empty UTF-8 substring
+ ///
+ /// # Panics
+ ///
+ /// Panics if `range` does not lie on valid `OsStr` boundaries or if it
+ /// exceeds the end of the string.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(os_str_slice)]
+ ///
+ /// use std::ffi::OsStr;
+ ///
+ /// let os_str = OsStr::new("foo=bar");
+ /// let bytes = os_str.as_encoded_bytes();
+ /// if let Some(index) = bytes.iter().position(|b| *b == b'=') {
+ /// let key = os_str.slice_encoded_bytes(..index);
+ /// let value = os_str.slice_encoded_bytes(index + 1..);
+ /// assert_eq!(key, "foo");
+ /// assert_eq!(value, "bar");
+ /// }
+ /// ```
+ #[unstable(feature = "os_str_slice", issue = "118485")]
+ pub fn slice_encoded_bytes<R: ops::RangeBounds<usize>>(&self, range: R) -> &Self {
+ #[track_caller]
+ fn check_valid_boundary(bytes: &[u8], index: usize) {
+ if index == 0 || index == bytes.len() {
+ return;
+ }
+
+ // Fast path
+ if bytes[index - 1].is_ascii() || bytes[index].is_ascii() {
+ return;
+ }
+
+ let (before, after) = bytes.split_at(index);
+
+ // UTF-8 takes at most 4 bytes per codepoint, so we don't
+ // need to check more than that.
+ let after = after.get(..4).unwrap_or(after);
+ match str_from_utf8(after) {
+ Ok(_) => return,
+ Err(err) if err.valid_up_to() != 0 => return,
+ Err(_) => (),
+ }
+
+ for len in 2..=4.min(index) {
+ let before = &before[index - len..];
+ if str_from_utf8(before).is_ok() {
+ return;
+ }
+ }
+
+ panic!("byte index {index} is not an OsStr boundary");
+ }
+
+ let encoded_bytes = self.as_encoded_bytes();
+ let Range { start, end } = slice::range(range, ..encoded_bytes.len());
+ check_valid_boundary(encoded_bytes, start);
+ check_valid_boundary(encoded_bytes, end);
+
+ // SAFETY: `slice::range` ensures that `start` and `end` are valid
+ let slice = unsafe { encoded_bytes.get_unchecked(start..end) };
+
+ // SAFETY: `slice` comes from `self` and we validated the boundaries
+ unsafe { Self::from_encoded_bytes_unchecked(slice) }
+ }
+
/// Converts this string to its ASCII lower case equivalent in-place.
///
/// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs
index d7926749a..60cde376d 100644
--- a/library/std/src/ffi/os_str/tests.rs
+++ b/library/std/src/ffi/os_str/tests.rs
@@ -1,8 +1,4 @@
use super::*;
-use crate::sys_common::{AsInner, IntoInner};
-
-use crate::rc::Rc;
-use crate::sync::Arc;
#[test]
fn test_os_string_with_capacity() {
@@ -177,3 +173,53 @@ fn into_rc() {
assert_eq!(&*rc2, os_str);
assert_eq!(&*arc2, os_str);
}
+
+#[test]
+fn slice_encoded_bytes() {
+ let os_str = OsStr::new("123θგ🦀");
+ // ASCII
+ let digits = os_str.slice_encoded_bytes(..3);
+ assert_eq!(digits, "123");
+ let three = os_str.slice_encoded_bytes(2..3);
+ assert_eq!(three, "3");
+ // 2-byte UTF-8
+ let theta = os_str.slice_encoded_bytes(3..5);
+ assert_eq!(theta, "θ");
+ // 3-byte UTF-8
+ let gani = os_str.slice_encoded_bytes(5..8);
+ assert_eq!(gani, "გ");
+ // 4-byte UTF-8
+ let crab = os_str.slice_encoded_bytes(8..);
+ assert_eq!(crab, "🦀");
+}
+
+#[test]
+#[should_panic(expected = "byte index 2 is not an OsStr boundary")]
+fn slice_mid_char() {
+ let crab = OsStr::new("🦀");
+ let _ = crab.slice_encoded_bytes(..2);
+}
+
+#[cfg(windows)]
+#[test]
+#[should_panic(expected = "byte index 3 is not an OsStr boundary")]
+fn slice_between_surrogates() {
+ use crate::os::windows::ffi::OsStringExt;
+
+ let os_string = OsString::from_wide(&[0xD800, 0xD800]);
+ assert_eq!(os_string.as_encoded_bytes(), &[0xED, 0xA0, 0x80, 0xED, 0xA0, 0x80]);
+ let _ = os_string.slice_encoded_bytes(..3);
+}
+
+#[cfg(windows)]
+#[test]
+fn slice_surrogate_edge() {
+ use crate::os::windows::ffi::OsStringExt;
+
+ let os_string = OsString::from_wide(&[0xD800]);
+ let mut with_crab = os_string.clone();
+ with_crab.push("🦀");
+
+ assert_eq!(with_crab.slice_encoded_bytes(..3), os_string);
+ assert_eq!(with_crab.slice_encoded_bytes(3..), "🦀");
+}
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 547a7b705..12afdef26 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -22,7 +22,7 @@ use crate::os::unix::fs::symlink as symlink_file;
#[cfg(unix)]
use crate::os::unix::fs::symlink as symlink_junction;
#[cfg(windows)]
-use crate::os::windows::fs::{symlink_dir, symlink_file};
+use crate::os::windows::fs::{symlink_dir, symlink_file, OpenOptionsExt};
#[cfg(windows)]
use crate::sys::fs::symlink_junction;
#[cfg(target_os = "macos")]
@@ -74,7 +74,7 @@ macro_rules! error_contains {
// tests most of the time, but at least we do if the user has the right
// permissions.
pub fn got_symlink_permission(tmpdir: &TempDir) -> bool {
- if cfg!(unix) {
+ if cfg!(not(windows)) || env::var_os("CI").is_some() {
return true;
}
let link = tmpdir.join("some_hopefully_unique_link_name");
@@ -1793,3 +1793,28 @@ fn windows_unix_socket_exists() {
assert_eq!(socket_path.try_exists().unwrap(), true);
assert_eq!(socket_path.metadata().is_ok(), true);
}
+
+#[cfg(windows)]
+#[test]
+fn test_hidden_file_truncation() {
+ // Make sure that File::create works on an existing hidden file. See #115745.
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("hidden_file.txt");
+
+ // Create a hidden file.
+ const FILE_ATTRIBUTE_HIDDEN: u32 = 2;
+ let mut file = OpenOptions::new()
+ .write(true)
+ .create_new(true)
+ .attributes(FILE_ATTRIBUTE_HIDDEN)
+ .open(&path)
+ .unwrap();
+ file.write("hidden world!".as_bytes()).unwrap();
+ file.flush().unwrap();
+ drop(file);
+
+ // Create a new file by truncating the existing one.
+ let file = File::create(&path).unwrap();
+ let metadata = file.metadata().unwrap();
+ assert_eq!(metadata.len(), 0);
+}
diff --git a/library/std/src/hash/mod.rs b/library/std/src/hash/mod.rs
new file mode 100644
index 000000000..e5ef9e335
--- /dev/null
+++ b/library/std/src/hash/mod.rs
@@ -0,0 +1,91 @@
+//! Generic hashing support.
+//!
+//! This module provides a generic way to compute the [hash] of a value.
+//! Hashes are most commonly used with [`HashMap`] and [`HashSet`].
+//!
+//! [hash]: https://en.wikipedia.org/wiki/Hash_function
+//! [`HashMap`]: ../../std/collections/struct.HashMap.html
+//! [`HashSet`]: ../../std/collections/struct.HashSet.html
+//!
+//! The simplest way to make a type hashable is to use `#[derive(Hash)]`:
+//!
+//! # Examples
+//!
+//! ```rust
+//! use std::hash::{DefaultHasher, Hash, Hasher};
+//!
+//! #[derive(Hash)]
+//! struct Person {
+//! id: u32,
+//! name: String,
+//! phone: u64,
+//! }
+//!
+//! let person1 = Person {
+//! id: 5,
+//! name: "Janet".to_string(),
+//! phone: 555_666_7777,
+//! };
+//! let person2 = Person {
+//! id: 5,
+//! name: "Bob".to_string(),
+//! phone: 555_666_7777,
+//! };
+//!
+//! assert!(calculate_hash(&person1) != calculate_hash(&person2));
+//!
+//! fn calculate_hash<T: Hash>(t: &T) -> u64 {
+//! let mut s = DefaultHasher::new();
+//! t.hash(&mut s);
+//! s.finish()
+//! }
+//! ```
+//!
+//! If you need more control over how a value is hashed, you need to implement
+//! the [`Hash`] trait:
+//!
+//! ```rust
+//! use std::hash::{DefaultHasher, Hash, Hasher};
+//!
+//! struct Person {
+//! id: u32,
+//! # #[allow(dead_code)]
+//! name: String,
+//! phone: u64,
+//! }
+//!
+//! impl Hash for Person {
+//! fn hash<H: Hasher>(&self, state: &mut H) {
+//! self.id.hash(state);
+//! self.phone.hash(state);
+//! }
+//! }
+//!
+//! let person1 = Person {
+//! id: 5,
+//! name: "Janet".to_string(),
+//! phone: 555_666_7777,
+//! };
+//! let person2 = Person {
+//! id: 5,
+//! name: "Bob".to_string(),
+//! phone: 555_666_7777,
+//! };
+//!
+//! assert_eq!(calculate_hash(&person1), calculate_hash(&person2));
+//!
+//! fn calculate_hash<T: Hash>(t: &T) -> u64 {
+//! let mut s = DefaultHasher::new();
+//! t.hash(&mut s);
+//! s.finish()
+//! }
+//! ```
+#![stable(feature = "rust1", since = "1.0.0")]
+
+pub(crate) mod random;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use core::hash::*;
+
+#[stable(feature = "std_hash_exports", since = "1.76.0")]
+pub use self::random::{DefaultHasher, RandomState};
diff --git a/library/std/src/hash/random.rs b/library/std/src/hash/random.rs
new file mode 100644
index 000000000..a1ccbb253
--- /dev/null
+++ b/library/std/src/hash/random.rs
@@ -0,0 +1,161 @@
+//! This module exists to isolate [`RandomState`] and [`DefaultHasher`] outside of the
+//! [`collections`] module without actually publicly exporting them, so that parts of that
+//! implementation can more easily be moved to the [`alloc`] crate.
+//!
+//! Although its items are public and contain stability attributes, they can't actually be accessed
+//! outside this crate.
+//!
+//! [`collections`]: crate::collections
+#[allow(deprecated)]
+use super::{BuildHasher, Hasher, SipHasher13};
+use crate::cell::Cell;
+use crate::fmt;
+use crate::sys;
+
+/// `RandomState` is the default state for [`HashMap`] types.
+///
+/// A particular instance `RandomState` will create the same instances of
+/// [`Hasher`], but the hashers created by two different `RandomState`
+/// instances are unlikely to produce the same result for the same values.
+///
+/// [`HashMap`]: crate::collections::HashMap
+///
+/// # Examples
+///
+/// ```
+/// use std::collections::HashMap;
+/// use std::hash::RandomState;
+///
+/// let s = RandomState::new();
+/// let mut map = HashMap::with_hasher(s);
+/// map.insert(1, 2);
+/// ```
+#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+#[derive(Clone)]
+pub struct RandomState {
+ k0: u64,
+ k1: u64,
+}
+
+impl RandomState {
+ /// Constructs a new `RandomState` that is initialized with random keys.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::hash::RandomState;
+ ///
+ /// let s = RandomState::new();
+ /// ```
+ #[inline]
+ #[allow(deprecated)]
+ // rand
+ #[must_use]
+ #[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+ pub fn new() -> RandomState {
+ // Historically this function did not cache keys from the OS and instead
+ // simply always called `rand::thread_rng().gen()` twice. In #31356 it
+ // was discovered, however, that because we re-seed the thread-local RNG
+ // from the OS periodically that this can cause excessive slowdown when
+ // many hash maps are created on a thread. To solve this performance
+ // trap we cache the first set of randomly generated keys per-thread.
+ //
+ // Later in #36481 it was discovered that exposing a deterministic
+ // iteration order allows a form of DOS attack. To counter that we
+ // increment one of the seeds on every RandomState creation, giving
+ // every corresponding HashMap a different iteration order.
+ thread_local!(static KEYS: Cell<(u64, u64)> = {
+ Cell::new(sys::hashmap_random_keys())
+ });
+
+ KEYS.with(|keys| {
+ let (k0, k1) = keys.get();
+ keys.set((k0.wrapping_add(1), k1));
+ RandomState { k0, k1 }
+ })
+ }
+}
+
+#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+impl BuildHasher for RandomState {
+ type Hasher = DefaultHasher;
+ #[inline]
+ #[allow(deprecated)]
+ fn build_hasher(&self) -> DefaultHasher {
+ DefaultHasher(SipHasher13::new_with_keys(self.k0, self.k1))
+ }
+}
+
+/// The default [`Hasher`] used by [`RandomState`].
+///
+/// The internal algorithm is not specified, and so it and its hashes should
+/// not be relied upon over releases.
+#[allow(deprecated)]
+#[derive(Clone, Debug)]
+#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+pub struct DefaultHasher(SipHasher13);
+
+impl DefaultHasher {
+ /// Creates a new `DefaultHasher`.
+ ///
+ /// This hasher is not guaranteed to be the same as all other
+ /// `DefaultHasher` instances, but is the same as all other `DefaultHasher`
+ /// instances created through `new` or `default`.
+ #[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
+ #[inline]
+ #[allow(deprecated)]
+ #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
+ #[must_use]
+ pub const fn new() -> DefaultHasher {
+ DefaultHasher(SipHasher13::new_with_keys(0, 0))
+ }
+}
+
+#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
+impl Default for DefaultHasher {
+ /// Creates a new `DefaultHasher` using [`new`].
+ /// See its documentation for more.
+ ///
+ /// [`new`]: DefaultHasher::new
+ #[inline]
+ fn default() -> DefaultHasher {
+ DefaultHasher::new()
+ }
+}
+
+#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
+impl Hasher for DefaultHasher {
+ // The underlying `SipHasher13` doesn't override the other
+ // `write_*` methods, so it's ok not to forward them here.
+
+ #[inline]
+ fn write(&mut self, msg: &[u8]) {
+ self.0.write(msg)
+ }
+
+ #[inline]
+ fn write_str(&mut self, s: &str) {
+ self.0.write_str(s);
+ }
+
+ #[inline]
+ fn finish(&self) -> u64 {
+ self.0.finish()
+ }
+}
+
+#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
+impl Default for RandomState {
+ /// Constructs a new `RandomState`.
+ #[inline]
+ fn default() -> RandomState {
+ RandomState::new()
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for RandomState {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("RandomState").finish_non_exhaustive()
+ }
+}
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
index 55aafc3db..6c7494a6a 100644
--- a/library/std/src/io/buffered/bufreader.rs
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -507,6 +507,16 @@ impl<R: ?Sized + Seek> Seek for BufReader<R> {
)
})
}
+
+ /// Seeks relative to the current position.
+ ///
+ /// If the new position lies within the buffer, the buffer will not be
+ /// flushed, allowing for more efficient seeks. This method does not return
+ /// the location of the underlying reader, so the caller must track this
+ /// information themselves if it is required.
+ fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
+ self.seek_relative(offset)
+ }
}
impl<T: ?Sized> SizeHint for BufReader<T> {
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index 4d51a719f..d49866345 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -1,7 +1,6 @@
use super::{BorrowedBuf, BufReader, BufWriter, Read, Result, Write, DEFAULT_BUF_SIZE};
use crate::alloc::Allocator;
use crate::cmp;
-use crate::cmp::min;
use crate::collections::VecDeque;
use crate::io::IoSlice;
use crate::mem::MaybeUninit;
@@ -256,79 +255,17 @@ impl<I: Write + ?Sized> BufferedWriterSpec for BufWriter<I> {
}
}
-impl<A: Allocator> BufferedWriterSpec for Vec<u8, A> {
+impl BufferedWriterSpec for Vec<u8> {
fn buffer_size(&self) -> usize {
cmp::max(DEFAULT_BUF_SIZE, self.capacity() - self.len())
}
fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
- let mut bytes = 0;
-
- // avoid inflating empty/small vecs before we have determined that there's anything to read
- if self.capacity() < DEFAULT_BUF_SIZE {
- let stack_read_limit = DEFAULT_BUF_SIZE as u64;
- bytes = stack_buffer_copy(&mut reader.take(stack_read_limit), self)?;
- // fewer bytes than requested -> EOF reached
- if bytes < stack_read_limit {
- return Ok(bytes);
- }
- }
-
- // don't immediately offer the vec's whole spare capacity, otherwise
- // we might have to fully initialize it if the reader doesn't have a custom read_buf() impl
- let mut max_read_size = DEFAULT_BUF_SIZE;
-
- loop {
- self.reserve(DEFAULT_BUF_SIZE);
- let mut initialized_spare_capacity = 0;
-
- loop {
- let buf = self.spare_capacity_mut();
- let read_size = min(max_read_size, buf.len());
- let mut buf = BorrowedBuf::from(&mut buf[..read_size]);
- // SAFETY: init is either 0 or the init_len from the previous iteration.
- unsafe {
- buf.set_init(initialized_spare_capacity);
- }
- match reader.read_buf(buf.unfilled()) {
- Ok(()) => {
- let bytes_read = buf.len();
-
- // EOF
- if bytes_read == 0 {
- return Ok(bytes);
- }
-
- // the reader is returning short reads but it doesn't call ensure_init()
- if buf.init_len() < buf.capacity() {
- max_read_size = usize::MAX;
- }
- // the reader hasn't returned short reads so far
- if bytes_read == buf.capacity() {
- max_read_size *= 2;
- }
-
- initialized_spare_capacity = buf.init_len() - bytes_read;
- bytes += bytes_read as u64;
- // SAFETY: BorrowedBuf guarantees all of its filled bytes are init
- // and the number of read bytes can't exceed the spare capacity since
- // that's what the buffer is borrowing from.
- unsafe { self.set_len(self.len() + bytes_read) };
-
- // spare capacity full, reserve more
- if self.len() == self.capacity() {
- break;
- }
- }
- Err(e) if e.is_interrupted() => continue,
- Err(e) => return Err(e),
- }
- }
- }
+ reader.read_to_end(self).map(|bytes| u64::try_from(bytes).expect("usize overflowed u64"))
}
}
-fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
+pub fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
reader: &mut R,
writer: &mut W,
) -> Result<u64> {
diff --git a/library/std/src/io/copy/tests.rs b/library/std/src/io/copy/tests.rs
index af137eaf8..a1f909a3c 100644
--- a/library/std/src/io/copy/tests.rs
+++ b/library/std/src/io/copy/tests.rs
@@ -82,13 +82,16 @@ fn copy_specializes_bufreader() {
#[test]
fn copy_specializes_to_vec() {
- let cap = 123456;
- let mut source = ShortReader { cap, observed_buffer: 0, read_size: 1337 };
+ let cap = DEFAULT_BUF_SIZE * 10;
+ let mut source = ShortReader { cap, observed_buffer: 0, read_size: DEFAULT_BUF_SIZE };
let mut sink = Vec::new();
- assert_eq!(cap as u64, io::copy(&mut source, &mut sink).unwrap());
+ let copied = io::copy(&mut source, &mut sink).unwrap();
+ assert_eq!(cap as u64, copied);
+ assert_eq!(sink.len() as u64, copied);
assert!(
source.observed_buffer > DEFAULT_BUF_SIZE,
- "expected a large buffer to be provided to the reader"
+ "expected a large buffer to be provided to the reader, got {}",
+ source.observed_buffer
);
}
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index 6e7366b36..db1756597 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -103,7 +103,6 @@
//! the time.
use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage};
-use alloc::boxed::Box;
use core::marker::PhantomData;
use core::mem::{align_of, size_of};
use core::ptr::{self, NonNull};
diff --git a/library/std/src/io/error/repr_unpacked.rs b/library/std/src/io/error/repr_unpacked.rs
index 093fde337..dc8a95577 100644
--- a/library/std/src/io/error/repr_unpacked.rs
+++ b/library/std/src/io/error/repr_unpacked.rs
@@ -3,7 +3,6 @@
//! would have no benefit.
use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage};
-use alloc::boxed::Box;
type Inner = ErrorData<Box<Custom>>;
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 7d70a0bac..e3aa97374 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -397,12 +397,16 @@ where
}
}
-// This uses an adaptive system to extend the vector when it fills. We want to
-// avoid paying to allocate and zero a huge chunk of memory if the reader only
-// has 4 bytes while still making large reads if the reader does have a ton
-// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
-// time is 4,500 times (!) slower than a default reservation size of 32 if the
-// reader has a very small amount of data to return.
+// Here we must serve many masters with conflicting goals:
+//
+// - avoid allocating unless necessary
+// - avoid overallocating if we know the exact size (#89165)
+// - avoid passing large buffers to readers that always initialize the free capacity if they perform short reads (#23815, #23820)
+// - pass large buffers to readers that do not initialize the spare capacity. this can amortize per-call overheads
+// - and finally pass not-too-small and not-too-large buffers to Windows read APIs because they manage to suffer from both problems
+// at the same time, i.e. small reads suffer from syscall overhead, all reads incur initialization cost
+// proportional to buffer size (#110650)
+//
pub(crate) fn default_read_to_end<R: Read + ?Sized>(
r: &mut R,
buf: &mut Vec<u8>,
@@ -412,20 +416,58 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(
let start_cap = buf.capacity();
// Optionally limit the maximum bytes read on each iteration.
// This adds an arbitrary fiddle factor to allow for more data than we expect.
- let max_read_size =
- size_hint.and_then(|s| s.checked_add(1024)?.checked_next_multiple_of(DEFAULT_BUF_SIZE));
+ let mut max_read_size = size_hint
+ .and_then(|s| s.checked_add(1024)?.checked_next_multiple_of(DEFAULT_BUF_SIZE))
+ .unwrap_or(DEFAULT_BUF_SIZE);
let mut initialized = 0; // Extra initialized bytes from previous loop iteration
+
+ const PROBE_SIZE: usize = 32;
+
+ fn small_probe_read<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
+ let mut probe = [0u8; PROBE_SIZE];
+
+ loop {
+ match r.read(&mut probe) {
+ Ok(n) => {
+ buf.extend_from_slice(&probe[..n]);
+ return Ok(n);
+ }
+ Err(ref e) if e.is_interrupted() => continue,
+ Err(e) => return Err(e),
+ }
+ }
+ }
+
+ // avoid inflating empty/small vecs before we have determined that there's anything to read
+ if (size_hint.is_none() || size_hint == Some(0)) && buf.capacity() - buf.len() < PROBE_SIZE {
+ let read = small_probe_read(r, buf)?;
+
+ if read == 0 {
+ return Ok(0);
+ }
+ }
+
loop {
+ if buf.len() == buf.capacity() && buf.capacity() == start_cap {
+ // The buffer might be an exact fit. Let's read into a probe buffer
+ // and see if it returns `Ok(0)`. If so, we've avoided an
+ // unnecessary doubling of the capacity. But if not, append the
+ // probe buffer to the primary buffer and let its capacity grow.
+ let read = small_probe_read(r, buf)?;
+
+ if read == 0 {
+ return Ok(buf.len() - start_len);
+ }
+ }
+
if buf.len() == buf.capacity() {
- buf.reserve(32); // buf is full, need more space
+ buf.reserve(PROBE_SIZE); // buf is full, need more space
}
let mut spare = buf.spare_capacity_mut();
- if let Some(size) = max_read_size {
- let len = cmp::min(spare.len(), size);
- spare = &mut spare[..len]
- }
+ let buf_len = cmp::min(spare.len(), max_read_size);
+ spare = &mut spare[..buf_len];
let mut read_buf: BorrowedBuf<'_> = spare.into();
// SAFETY: These bytes were initialized but not filled in the previous loop
@@ -434,42 +476,44 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(
}
let mut cursor = read_buf.unfilled();
- match r.read_buf(cursor.reborrow()) {
- Ok(()) => {}
- Err(e) if e.is_interrupted() => continue,
- Err(e) => return Err(e),
+ loop {
+ match r.read_buf(cursor.reborrow()) {
+ Ok(()) => break,
+ Err(e) if e.is_interrupted() => continue,
+ Err(e) => return Err(e),
+ }
}
- if cursor.written() == 0 {
+ let unfilled_but_initialized = cursor.init_ref().len();
+ let bytes_read = cursor.written();
+ let was_fully_initialized = read_buf.init_len() == buf_len;
+
+ if bytes_read == 0 {
return Ok(buf.len() - start_len);
}
// store how much was initialized but not filled
- initialized = cursor.init_ref().len();
+ initialized = unfilled_but_initialized;
// SAFETY: BorrowedBuf's invariants mean this much memory is initialized.
unsafe {
- let new_len = read_buf.filled().len() + buf.len();
+ let new_len = bytes_read + buf.len();
buf.set_len(new_len);
}
- if buf.len() == buf.capacity() && buf.capacity() == start_cap {
- // The buffer might be an exact fit. Let's read into a probe buffer
- // and see if it returns `Ok(0)`. If so, we've avoided an
- // unnecessary doubling of the capacity. But if not, append the
- // probe buffer to the primary buffer and let its capacity grow.
- let mut probe = [0u8; 32];
-
- loop {
- match r.read(&mut probe) {
- Ok(0) => return Ok(buf.len() - start_len),
- Ok(n) => {
- buf.extend_from_slice(&probe[..n]);
- break;
- }
- Err(ref e) if e.is_interrupted() => continue,
- Err(e) => return Err(e),
- }
+ // Use heuristics to determine the max read size if no initial size hint was provided
+ if size_hint.is_none() {
+ // The reader is returning short reads but it doesn't call ensure_init().
+ // In that case we no longer need to restrict read sizes to avoid
+ // initialization costs.
+ if !was_fully_initialized {
+ max_read_size = usize::MAX;
+ }
+
+ // we have passed a larger buffer than previously and the
+ // reader still hasn't returned a short read
+ if buf_len >= max_read_size && bytes_read == buf_len {
+ max_read_size = max_read_size.saturating_mul(2);
}
}
}
@@ -556,6 +600,10 @@ where
/// therefore, using something that implements [`BufRead`], such as
/// [`BufReader`], will be more efficient.
///
+/// Repeated calls to the reader use the same cursor, so for example
+/// calling `read_to_end` twice on a [`File`] will only return the file's
+/// contents once. It's recommended to first call `rewind()` in that case.
+///
/// # Examples
///
/// [`File`]s implement `Read`:
@@ -1957,6 +2005,36 @@ pub trait Seek {
fn stream_position(&mut self) -> Result<u64> {
self.seek(SeekFrom::Current(0))
}
+
+ /// Seeks relative to the current position.
+ ///
+ /// This is equivalent to `self.seek(SeekFrom::Current(offset))` but
+ /// doesn't return the new position which can allow some implementations
+ /// such as [`BufReader`] to perform more efficient seeks.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// #![feature(seek_seek_relative)]
+ /// use std::{
+ /// io::{self, Seek},
+ /// fs::File,
+ /// };
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut f = File::open("foo.txt")?;
+ /// f.seek_relative(10)?;
+ /// assert_eq!(f.stream_position()?, 10);
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [`BufReader`]: crate::io::BufReader
+ #[unstable(feature = "seek_seek_relative", issue = "117374")]
+ fn seek_relative(&mut self, offset: i64) -> Result<()> {
+ self.seek(SeekFrom::Current(offset))?;
+ Ok(())
+ }
}
/// Enumeration of possible methods to seek within an I/O object.
@@ -2014,6 +2092,28 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) -> R
}
}
+fn skip_until<R: BufRead + ?Sized>(r: &mut R, delim: u8) -> Result<usize> {
+ let mut read = 0;
+ loop {
+ let (done, used) = {
+ let available = match r.fill_buf() {
+ Ok(n) => n,
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(e) => return Err(e),
+ };
+ match memchr::memchr(delim, available) {
+ Some(i) => (true, i + 1),
+ None => (false, available.len()),
+ }
+ };
+ r.consume(used);
+ read += used;
+ if done || used == 0 {
+ return Ok(read);
+ }
+ }
+}
+
/// A `BufRead` is a type of `Read`er which has an internal buffer, allowing it
/// to perform extra ways of reading.
///
@@ -2217,6 +2317,68 @@ pub trait BufRead: Read {
read_until(self, byte, buf)
}
+ /// Skip all bytes until the delimiter `byte` or EOF is reached.
+ ///
+ /// This function will read (and discard) bytes from the underlying stream until the
+ /// delimiter or EOF is found.
+ ///
+ /// If successful, this function will return the total number of bytes read,
+ /// including the delimiter byte.
+ ///
+ /// This is useful for efficiently skipping data such as NUL-terminated strings
+ /// in binary file formats without buffering.
+ ///
+ /// This function is blocking and should be used carefully: it is possible for
+ /// an attacker to continuously send bytes without ever sending the delimiter
+ /// or EOF.
+ ///
+ /// # Errors
+ ///
+ /// This function will ignore all instances of [`ErrorKind::Interrupted`] and
+ /// will otherwise return any errors returned by [`fill_buf`].
+ ///
+ /// If an I/O error is encountered then all bytes read so far will be
+ /// present in `buf` and its length will have been adjusted appropriately.
+ ///
+ /// [`fill_buf`]: BufRead::fill_buf
+ ///
+ /// # Examples
+ ///
+ /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+ /// this example, we use [`Cursor`] to read some NUL-terminated information
+ /// about Ferris from a binary string, skipping the fun fact:
+ ///
+ /// ```
+ /// #![feature(bufread_skip_until)]
+ ///
+ /// use std::io::{self, BufRead};
+ ///
+ /// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0");
+ ///
+ /// // read name
+ /// let mut name = Vec::new();
+ /// let num_bytes = cursor.read_until(b'\0', &mut name)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 7);
+ /// assert_eq!(name, b"Ferris\0");
+ ///
+ /// // skip fun fact
+ /// let num_bytes = cursor.skip_until(b'\0')
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 30);
+ ///
+ /// // read animal type
+ /// let mut animal = Vec::new();
+ /// let num_bytes = cursor.read_until(b'\0', &mut animal)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 11);
+ /// assert_eq!(animal, b"Crustacean\0");
+ /// ```
+ #[unstable(feature = "bufread_skip_until", issue = "111735")]
+ fn skip_until(&mut self, byte: u8) -> Result<usize> {
+ skip_until(self, byte)
+ }
+
/// Read all bytes until a newline (the `0xA` byte) is reached, and append
/// them to the provided `String` buffer.
///
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index 6d30f5e6c..bda5b721a 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -26,6 +26,36 @@ fn read_until() {
}
#[test]
+fn skip_until() {
+ let bytes: &[u8] = b"read\0ignore\0read\0ignore\0read\0ignore\0";
+ let mut reader = BufReader::new(bytes);
+
+ // read from the bytes, alternating between
+ // consuming `read\0`s and skipping `ignore\0`s
+ loop {
+ // consume `read\0`
+ let mut out = Vec::new();
+ let read = reader.read_until(0, &mut out).unwrap();
+ if read == 0 {
+ // eof
+ break;
+ } else {
+ assert_eq!(out, b"read\0");
+ assert_eq!(read, b"read\0".len());
+ }
+
+ // skip past `ignore\0`
+ let skipped = reader.skip_until(0).unwrap();
+ assert_eq!(skipped, b"ignore\0".len());
+ }
+
+ // ensure we are at the end of the byte slice and that we can skip no further
+ // also ensure skip_until matches the behavior of read_until at EOF
+ let skipped = reader.skip_until(0).unwrap();
+ assert_eq!(skipped, 0);
+}
+
+#[test]
fn split() {
let buf = Cursor::new(&b"12"[..]);
let mut s = buf.split(b'3');
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 425890122..34b381b6c 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -227,7 +227,7 @@
test(no_crate_inject, attr(deny(warnings))),
test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
)]
-#![cfg_attr(not(bootstrap), doc(rust_logo))]
+#![doc(rust_logo)]
#![doc(cfg_hide(
not(test),
not(any(test, bootstrap)),
@@ -308,6 +308,7 @@
//
// Library features (core):
// tidy-alphabetical-start
+#![feature(c_str_literals)]
#![feature(char_internals)]
#![feature(core_intrinsics)]
#![feature(core_io_borrowed_buf)]
@@ -317,6 +318,7 @@
#![feature(error_iter)]
#![feature(exact_size_is_empty)]
#![feature(exclusive_wrapper)]
+#![feature(exposed_provenance)]
#![feature(extend_one)]
#![feature(float_gamma)]
#![feature(float_minimum_maximum)]
@@ -340,6 +342,7 @@
#![feature(round_ties_even)]
#![feature(slice_internals)]
#![feature(slice_ptr_get)]
+#![feature(slice_range)]
#![feature(std_internals)]
#![feature(str_internals)]
#![feature(strict_provenance)]
@@ -494,8 +497,6 @@ pub use core::convert;
pub use core::default;
#[stable(feature = "futures_api", since = "1.36.0")]
pub use core::future;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use core::hash;
#[stable(feature = "core_hint", since = "1.27.0")]
pub use core::hint;
#[stable(feature = "i128", since = "1.26.0")]
@@ -565,6 +566,7 @@ pub mod env;
pub mod error;
pub mod ffi;
pub mod fs;
+pub mod hash;
pub mod io;
pub mod net;
pub mod num;
@@ -583,9 +585,10 @@ pub mod time;
#[unstable(feature = "portable_simd", issue = "86656")]
mod std_float;
-#[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
#[unstable(feature = "portable_simd", issue = "86656")]
pub mod simd {
+ #![doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")]
+
#[doc(inline)]
pub use crate::std_float::StdFloat;
#[doc(inline)]
@@ -716,7 +719,7 @@ pub(crate) mod test_helpers {
#[track_caller]
pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
use core::hash::{BuildHasher, Hash, Hasher};
- let mut hasher = crate::collections::hash_map::RandomState::new().build_hasher();
+ let mut hasher = crate::hash::RandomState::new().build_hasher();
core::panic::Location::caller().hash(&mut hasher);
let hc64 = hasher.finish();
let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();
diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index 34b8b6b97..58df83bd7 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -355,15 +355,15 @@ macro_rules! dbg {
// `$val` expression could be a block (`{ .. }`), in which case the `eprintln!`
// will be malformed.
() => {
- $crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!())
+ $crate::eprintln!("[{}:{}:{}]", $crate::file!(), $crate::line!(), $crate::column!())
};
($val:expr $(,)?) => {
// Use of `match` here is intentional because it affects the lifetimes
// of temporaries - https://stackoverflow.com/a/48732525/1063961
match $val {
tmp => {
- $crate::eprintln!("[{}:{}] {} = {:#?}",
- $crate::file!(), $crate::line!(), $crate::stringify!($val), &tmp);
+ $crate::eprintln!("[{}:{}:{}] {} = {:#?}",
+ $crate::file!(), $crate::line!(), $crate::column!(), $crate::stringify!($val), &tmp);
tmp
}
}
diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs
index db367cfa0..b24b851a6 100644
--- a/library/std/src/net/tcp/tests.rs
+++ b/library/std/src/net/tcp/tests.rs
@@ -1,6 +1,6 @@
use crate::fmt;
use crate::io::prelude::*;
-use crate::io::{BorrowedBuf, ErrorKind, IoSlice, IoSliceMut};
+use crate::io::{BorrowedBuf, IoSlice, IoSliceMut};
use crate::mem::MaybeUninit;
use crate::net::test::{next_test_ip4, next_test_ip6};
use crate::net::*;
diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs
index 892fe2ba8..0cf993664 100644
--- a/library/std/src/net/udp/tests.rs
+++ b/library/std/src/net/udp/tests.rs
@@ -1,4 +1,3 @@
-use crate::io::ErrorKind;
use crate::net::test::{next_test_ip4, next_test_ip6};
use crate::net::*;
use crate::sync::mpsc::channel;
diff --git a/library/std/src/os/l4re/raw.rs b/library/std/src/os/l4re/raw.rs
index 12c029328..8fb6e99ec 100644
--- a/library/std/src/os/l4re/raw.rs
+++ b/library/std/src/os/l4re/raw.rs
@@ -31,7 +31,6 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
target_arch = "powerpc",
target_arch = "sparc",
target_arch = "arm",
- target_arch = "asmjs",
target_arch = "wasm32"
))]
mod arch {
diff --git a/library/std/src/os/linux/process.rs b/library/std/src/os/linux/process.rs
index 2b3ff76d7..51af432d0 100644
--- a/library/std/src/os/linux/process.rs
+++ b/library/std/src/os/linux/process.rs
@@ -152,6 +152,12 @@ pub trait CommandExt: Sealed {
/// in a guaranteed race-free manner (e.g. if the `clone3` system call
/// is supported). Otherwise, [`pidfd`] will return an error.
///
+ /// If a pidfd has been successfully created and not been taken from the `Child`
+ /// then calls to `kill()`, `wait()` and `try_wait()` will use the pidfd
+ /// instead of the pid. This can prevent pid recycling races, e.g.
+ /// those caused by rogue libraries in the same process prematurely reaping
+ /// zombie children via `waitpid(-1, ...)` calls.
+ ///
/// [`Command`]: process::Command
/// [`Child`]: process::Child
/// [`pidfd`]: fn@ChildExt::pidfd
diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs
index a568f9b26..c29dd62bc 100644
--- a/library/std/src/os/linux/raw.rs
+++ b/library/std/src/os/linux/raw.rs
@@ -31,7 +31,6 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
target_arch = "powerpc",
target_arch = "sparc",
target_arch = "arm",
- target_arch = "asmjs",
target_arch = "wasm32"
))]
mod arch {
diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs
index f82034663..19b4fe220 100644
--- a/library/std/src/os/solid/io.rs
+++ b/library/std/src/os/solid/io.rs
@@ -1,8 +1,55 @@
//! SOLID-specific extensions to general I/O primitives
+//!
+//! Just like raw pointers, raw SOLID Sockets file descriptors point to
+//! resources with dynamic lifetimes, and they can dangle if they outlive their
+//! resources or be forged if they're created from invalid values.
+//!
+//! This module provides three types for representing raw file descriptors
+//! with different ownership properties: raw, borrowed, and owned, which are
+//! analogous to types used for representing pointers:
+//!
+//! | Type | Analogous to |
+//! | ------------------ | ------------ |
+//! | [`RawFd`] | `*const _` |
+//! | [`BorrowedFd<'a>`] | `&'a _` |
+//! | [`OwnedFd`] | `Box<_>` |
+//!
+//! Like raw pointers, `RawFd` values are primitive values. And in new code,
+//! they should be considered unsafe to do I/O on (analogous to dereferencing
+//! them). Rust did not always provide this guidance, so existing code in the
+//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Once the
+//! `io_safety` feature is stable, libraries will be encouraged to migrate,
+//! either by adding `unsafe` to APIs that dereference `RawFd` values, or by
+//! using to `BorrowedFd` or `OwnedFd` instead.
+//!
+//! Like references, `BorrowedFd` values are tied to a lifetime, to ensure
+//! that they don't outlive the resource they point to. These are safe to
+//! use. `BorrowedFd` values may be used in APIs which provide safe access to
+//! any system call except for:
+//!
+//! - `close`, because that would end the dynamic lifetime of the resource
+//! without ending the lifetime of the file descriptor.
+//!
+//! - `dup2`/`dup3`, in the second argument, because this argument is
+//! closed and assigned a new resource, which may break the assumptions
+//! other code using that file descriptor.
+//!
+//! `BorrowedFd` values may be used in APIs which provide safe access to `dup`
+//! system calls, so types implementing `AsFd` or `From<OwnedFd>` should not
+//! assume they always have exclusive access to the underlying file
+//! description.
+//!
+//! Like boxes, `OwnedFd` values conceptually own the resource they point to,
+//! and free (close) it when they are dropped.
+//!
+//! [`BorrowedFd<'a>`]: crate::os::solid::io::BorrowedFd
#![deny(unsafe_op_in_unsafe_fn)]
#![unstable(feature = "solid_ext", issue = "none")]
+use crate::fmt;
+use crate::marker::PhantomData;
+use crate::mem::forget;
use crate::net;
use crate::sys;
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
@@ -10,6 +57,253 @@ use crate::sys_common::{self, AsInner, FromInner, IntoInner};
/// Raw file descriptors.
pub type RawFd = i32;
+/// A borrowed SOLID Sockets file descriptor.
+///
+/// This has a lifetime parameter to tie it to the lifetime of something that
+/// owns the socket.
+///
+/// This uses `repr(transparent)` and has the representation of a host file
+/// descriptor, so it can be used in FFI in places where a socket is passed as
+/// an argument, it is not captured or consumed, and it never has the value
+/// `SOLID_NET_INVALID_FD`.
+///
+/// This type's `.to_owned()` implementation returns another `BorrowedFd`
+/// rather than an `OwnedFd`. It just makes a trivial copy of the raw
+/// socket, which is then borrowed under the same lifetime.
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// This is -2, in two's complement. -1 is `SOLID_NET_INVALID_FD`.
+#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
+#[rustc_nonnull_optimization_guaranteed]
+pub struct BorrowedFd<'socket> {
+ fd: RawFd,
+ _phantom: PhantomData<&'socket OwnedFd>,
+}
+
+/// An owned SOLID Sockets file descriptor.
+///
+/// This closes the file descriptor on drop.
+///
+/// This uses `repr(transparent)` and has the representation of a host file
+/// descriptor, so it can be used in FFI in places where a socket is passed as
+/// an argument, it is not captured or consumed, and it never has the value
+/// `SOLID_NET_INVALID_FD`.
+#[repr(transparent)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// This is -2, in two's complement. -1 is `SOLID_NET_INVALID_FD`.
+#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
+#[rustc_nonnull_optimization_guaranteed]
+pub struct OwnedFd {
+ fd: RawFd,
+}
+
+impl BorrowedFd<'_> {
+ /// Return a `BorrowedFd` holding the given raw file descriptor.
+ ///
+ /// # Safety
+ ///
+ /// The resource pointed to by `fd` must remain open for the duration of
+ /// the returned `BorrowedFd`, and it must not have the value
+ /// `SOLID_NET_INVALID_FD`.
+ #[inline]
+ pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
+ assert!(fd != -1 as RawFd);
+ // SAFETY: we just asserted that the value is in the valid range and
+ // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
+ unsafe { Self { fd, _phantom: PhantomData } }
+ }
+}
+
+impl OwnedFd {
+ /// Creates a new `OwnedFd` instance that shares the same underlying file
+ /// description as the existing `OwnedFd` instance.
+ pub fn try_clone(&self) -> crate::io::Result<Self> {
+ self.as_fd().try_clone_to_owned()
+ }
+}
+
+impl BorrowedFd<'_> {
+ /// Creates a new `OwnedFd` instance that shares the same underlying file
+ /// description as the existing `BorrowedFd` instance.
+ pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
+ let fd = sys::net::cvt(unsafe { sys::net::netc::dup(self.as_raw_fd()) })?;
+ Ok(unsafe { OwnedFd::from_raw_fd(fd) })
+ }
+}
+
+impl AsRawFd for BorrowedFd<'_> {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.fd
+ }
+}
+
+impl AsRawFd for OwnedFd {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.fd
+ }
+}
+
+impl IntoRawFd for OwnedFd {
+ #[inline]
+ fn into_raw_fd(self) -> RawFd {
+ let fd = self.fd;
+ forget(self);
+ fd
+ }
+}
+
+impl FromRawFd for OwnedFd {
+ /// Constructs a new instance of `Self` from the given raw file descriptor.
+ ///
+ /// # Safety
+ ///
+ /// The resource pointed to by `fd` must be open and suitable for assuming
+ /// ownership. The resource must not require any cleanup other than `close`.
+ #[inline]
+ unsafe fn from_raw_fd(fd: RawFd) -> Self {
+ assert_ne!(fd, -1 as RawFd);
+ // SAFETY: we just asserted that the value is in the valid range and
+ // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
+ unsafe { Self { fd } }
+ }
+}
+
+impl Drop for OwnedFd {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe { sys::net::netc::close(self.fd) };
+ }
+}
+
+impl fmt::Debug for BorrowedFd<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
+ }
+}
+
+impl fmt::Debug for OwnedFd {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
+ }
+}
+
+macro_rules! impl_is_terminal {
+ ($($t:ty),*$(,)?) => {$(
+ #[unstable(feature = "sealed", issue = "none")]
+ impl crate::sealed::Sealed for $t {}
+
+ #[stable(feature = "is_terminal", since = "1.70.0")]
+ impl crate::io::IsTerminal for $t {
+ #[inline]
+ fn is_terminal(&self) -> bool {
+ crate::sys::io::is_terminal(self)
+ }
+ }
+ )*}
+}
+
+impl_is_terminal!(BorrowedFd<'_>, OwnedFd);
+
+/// A trait to borrow the SOLID Sockets file descriptor from an underlying
+/// object.
+pub trait AsFd {
+ /// Borrows the file descriptor.
+ fn as_fd(&self) -> BorrowedFd<'_>;
+}
+
+impl<T: AsFd> AsFd for &T {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ T::as_fd(self)
+ }
+}
+
+impl<T: AsFd> AsFd for &mut T {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ T::as_fd(self)
+ }
+}
+
+impl AsFd for BorrowedFd<'_> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ *self
+ }
+}
+
+impl AsFd for OwnedFd {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ // Safety: `OwnedFd` and `BorrowedFd` have the same validity
+ // invariants, and the `BorrowedFd` is bounded by the lifetime
+ // of `&self`.
+ unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
+ }
+}
+
+macro_rules! impl_owned_fd_traits {
+ ($($t:ident)*) => {$(
+ impl AsFd for net::$t {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.as_inner().socket().as_fd()
+ }
+ }
+
+ impl From<net::$t> for OwnedFd {
+ #[inline]
+ fn from(socket: net::$t) -> OwnedFd {
+ socket.into_inner().into_socket().into_inner()
+ }
+ }
+
+ impl From<OwnedFd> for net::$t {
+ #[inline]
+ fn from(owned_fd: OwnedFd) -> Self {
+ Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
+ }
+ }
+ )*};
+}
+impl_owned_fd_traits! { TcpStream TcpListener UdpSocket }
+
+/// This impl allows implementing traits that require `AsFd` on Arc.
+/// ```
+/// # #[cfg(target_os = "solid_asp3")] mod group_cfg {
+/// # use std::os::solid::io::AsFd;
+/// use std::net::UdpSocket;
+/// use std::sync::Arc;
+///
+/// trait MyTrait: AsFd {}
+/// impl MyTrait for Arc<UdpSocket> {}
+/// impl MyTrait for Box<UdpSocket> {}
+/// # }
+/// ```
+impl<T: AsFd> AsFd for crate::sync::Arc<T> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ (**self).as_fd()
+ }
+}
+
+impl<T: AsFd> AsFd for crate::rc::Rc<T> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ (**self).as_fd()
+ }
+}
+
+impl<T: AsFd> AsFd for Box<T> {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ (**self).as_fd()
+ }
+}
+
/// A trait to extract the raw SOLID Sockets file descriptor from an underlying
/// object.
pub trait AsRawFd {
@@ -84,7 +378,7 @@ macro_rules! impl_as_raw_fd {
impl AsRawFd for net::$t {
#[inline]
fn as_raw_fd(&self) -> RawFd {
- *self.as_inner().socket().as_inner()
+ self.as_inner().socket().as_raw_fd()
}
}
)*};
@@ -97,7 +391,7 @@ macro_rules! impl_from_raw_fd {
impl FromRawFd for net::$t {
#[inline]
unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
- let socket = sys::net::Socket::from_inner(fd);
+ let socket = unsafe { sys::net::Socket::from_raw_fd(fd) };
net::$t::from_inner(sys_common::net::$t::from_inner(socket))
}
}
@@ -111,7 +405,7 @@ macro_rules! impl_into_raw_fd {
impl IntoRawFd for net::$t {
#[inline]
fn into_raw_fd(self) -> RawFd {
- self.into_inner().into_socket().into_inner()
+ self.into_inner().into_socket().into_raw_fd()
}
}
)*};
diff --git a/library/std/src/os/solid/mod.rs b/library/std/src/os/solid/mod.rs
index 4328ba7c3..0bb83c73d 100644
--- a/library/std/src/os/solid/mod.rs
+++ b/library/std/src/os/solid/mod.rs
@@ -13,5 +13,5 @@ pub mod prelude {
pub use super::ffi::{OsStrExt, OsStringExt};
#[doc(no_inline)]
#[stable(feature = "rust1", since = "1.0.0")]
- pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+ pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
}
diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
index 274af08a3..b0540872c 100644
--- a/library/std/src/os/windows/io/handle.rs
+++ b/library/std/src/os/windows/io/handle.rs
@@ -504,7 +504,7 @@ impl AsHandle for fs::File {
impl From<fs::File> for OwnedHandle {
#[inline]
fn from(file: fs::File) -> OwnedHandle {
- file.into_inner().into_inner().into_inner().into()
+ file.into_inner().into_inner().into_inner()
}
}
diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs
index c80b9e284..65f161f32 100644
--- a/library/std/src/os/windows/io/socket.rs
+++ b/library/std/src/os/windows/io/socket.rs
@@ -127,7 +127,7 @@ impl BorrowedSocket<'_> {
info.iAddressFamily,
info.iSocketType,
info.iProtocol,
- &mut info,
+ &info,
0,
sys::c::WSA_FLAG_OVERLAPPED | sys::c::WSA_FLAG_NO_HANDLE_INHERIT,
)
@@ -147,7 +147,7 @@ impl BorrowedSocket<'_> {
info.iAddressFamily,
info.iSocketType,
info.iProtocol,
- &mut info,
+ &info,
0,
sys::c::WSA_FLAG_OVERLAPPED,
)
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index d00e79476..5bf0154ea 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -347,7 +347,7 @@ impl ChildExt for process::Child {
///
/// This trait is sealed: it cannot be implemented outside the standard library.
/// This is so that future additional methods are not breaking changes.
-#[unstable(feature = "windows_process_exit_code_from", issue = "none")]
+#[unstable(feature = "windows_process_exit_code_from", issue = "111688")]
pub trait ExitCodeExt: Sealed {
/// Creates a new `ExitCode` from the raw underlying `u32` return value of
/// a process.
@@ -355,11 +355,11 @@ pub trait ExitCodeExt: Sealed {
/// The exit code should not be 259, as this conflicts with the `STILL_ACTIVE`
/// macro returned from the `GetExitCodeProcess` function to signal that the
/// process has yet to run to completion.
- #[unstable(feature = "windows_process_exit_code_from", issue = "none")]
+ #[unstable(feature = "windows_process_exit_code_from", issue = "111688")]
fn from_raw(raw: u32) -> Self;
}
-#[unstable(feature = "windows_process_exit_code_from", issue = "none")]
+#[unstable(feature = "windows_process_exit_code_from", issue = "111688")]
impl ExitCodeExt for process::ExitCode {
fn from_raw(raw: u32) -> Self {
process::ExitCode::from_inner(From::from(raw))
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 55f4917a9..66b4ec37c 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -588,7 +588,7 @@ pub fn panicking() -> bool {
}
/// Entry point of panics from the core crate (`panic_impl` lang item).
-#[cfg(not(test))]
+#[cfg(not(any(test, doctest)))]
#[panic_handler]
pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
struct FormatStringPayload<'a> {
@@ -669,7 +669,7 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
/// panic!() and assert!(). In particular, this is the only entry point that supports
/// arbitrary payloads, not just format strings.
#[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")]
-#[cfg_attr(not(test), lang = "begin_panic")]
+#[cfg_attr(not(any(test, doctest)), lang = "begin_panic")]
// lang item for CTFE panic support
// never inline unless panic_immediate_abort to avoid code
// bloat at the call sites as much as possible
diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs
index f12ffbf2e..fde6ed4f0 100644
--- a/library/std/src/path/tests.rs
+++ b/library/std/src/path/tests.rs
@@ -1,10 +1,7 @@
use super::*;
-use crate::collections::hash_map::DefaultHasher;
use crate::collections::{BTreeSet, HashSet};
-use crate::hash::Hasher;
-use crate::rc::Rc;
-use crate::sync::Arc;
+use crate::hash::DefaultHasher;
use core::hint::black_box;
#[allow(unknown_lints, unused_macro_rules)]
@@ -1461,8 +1458,7 @@ fn test_eq_receivers() {
#[test]
pub fn test_compare() {
- use crate::collections::hash_map::DefaultHasher;
- use crate::hash::{Hash, Hasher};
+ use crate::hash::{DefaultHasher, Hash, Hasher};
fn hash<T: Hash>(t: T) -> u64 {
let mut s = DefaultHasher::new();
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index af6bef1a7..4a7f5d8e0 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1108,7 +1108,7 @@ impl fmt::Debug for Command {
///
/// The default format approximates a shell invocation of the program along with its
/// arguments. It does not include most of the other command properties. The output is not guaranteed to work
- /// (e.g. due to lack of shell-escaping or differences in path resolution)
+ /// (e.g. due to lack of shell-escaping or differences in path resolution).
/// On some platforms you can use [the alternate syntax] to show more fields.
///
/// Note that the debug implementation is platform-specific.
@@ -2311,7 +2311,7 @@ pub fn id() -> u32 {
/// of the `main` function, this trait is likely to be available only on
/// standard library's runtime for convenience. Other runtimes are not required
/// to provide similar functionality.
-#[cfg_attr(not(test), lang = "termination")]
+#[cfg_attr(not(any(test, doctest)), lang = "termination")]
#[stable(feature = "termination_trait_lib", since = "1.61.0")]
#[rustc_on_unimplemented(on(
cause = "MainFunctionType",
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 5c83f72f3..335944845 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -154,8 +154,7 @@ fn lang_start_internal(
ret_code
}
-#[cfg(not(test))]
-#[inline(never)]
+#[cfg(not(any(test, doctest)))]
#[lang = "start"]
fn lang_start<T: crate::process::Termination + 'static>(
main: fn() -> T,
diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/src/sync/mpsc/sync_tests.rs
index 632709fd9..945de280f 100644
--- a/library/std/src/sync/mpsc/sync_tests.rs
+++ b/library/std/src/sync/mpsc/sync_tests.rs
@@ -3,7 +3,6 @@ use crate::env;
use crate::rc::Rc;
use crate::sync::mpmc::SendTimeoutError;
use crate::thread;
-use crate::time::Duration;
pub fn stress_factor() -> usize {
match env::var("RUST_TEST_STRESS") {
diff --git a/library/std/src/sync/mpsc/tests.rs b/library/std/src/sync/mpsc/tests.rs
index 1e52a4a70..ac1a804cf 100644
--- a/library/std/src/sync/mpsc/tests.rs
+++ b/library/std/src/sync/mpsc/tests.rs
@@ -1,7 +1,6 @@
use super::*;
use crate::env;
use crate::thread;
-use crate::time::{Duration, Instant};
pub fn stress_factor() -> usize {
match env::var("RUST_TEST_STRESS") {
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index b4ae6b7e0..0c001d7c2 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -146,7 +146,7 @@ use crate::sys::locks as sys;
/// let result = data.iter().fold(0, |acc, x| acc + x * 2);
/// data.push(result);
/// // We drop the `data` explicitly because it's not necessary anymore and the
-/// // thread still has work to do. This allow other threads to start working on
+/// // thread still has work to do. This allows other threads to start working on
/// // the data immediately, without waiting for the rest of the unrelated work
/// // to be done here.
/// //
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index f49630907..b8873a3b5 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -13,22 +13,65 @@ use crate::sync::Once;
///
/// # Examples
///
+/// Using `OnceCell` to store a function’s previously computed value (a.k.a.
+/// ‘lazy static’ or ‘memoizing’):
+///
/// ```
/// use std::sync::OnceLock;
///
-/// static CELL: OnceLock<String> = OnceLock::new();
+/// struct DeepThought {
+/// answer: String,
+/// }
+///
+/// impl DeepThought {
+/// # fn great_question() -> String {
+/// # "42".to_string()
+/// # }
+/// #
+/// fn new() -> Self {
+/// Self {
+/// // M3 Ultra takes about 16 million years in --release config
+/// answer: Self::great_question(),
+/// }
+/// }
+/// }
+///
+/// fn computation() -> &'static DeepThought {
+/// // n.b. static items do not call [`Drop`] on program termination, so if
+/// // [`DeepThought`] impls Drop, that will not be used for this instance.
+/// static COMPUTATION: OnceLock<DeepThought> = OnceLock::new();
+/// COMPUTATION.get_or_init(|| DeepThought::new())
+/// }
+///
+/// // The `DeepThought` is built, stored in the `OnceLock`, and returned.
+/// let _ = computation().answer;
+/// // The `DeepThought` is retrieved from the `OnceLock` and returned.
+/// let _ = computation().answer;
+/// ```
+///
+/// Writing to a `OnceLock` from a separate thread:
+///
+/// ```
+/// use std::sync::OnceLock;
+///
+/// static CELL: OnceLock<usize> = OnceLock::new();
+///
+/// // `OnceLock` has not been written to yet.
/// assert!(CELL.get().is_none());
///
+/// // Spawn a thread and write to `OnceLock`.
/// std::thread::spawn(|| {
-/// let value: &String = CELL.get_or_init(|| {
-/// "Hello, World!".to_string()
-/// });
-/// assert_eq!(value, "Hello, World!");
-/// }).join().unwrap();
+/// let value = CELL.get_or_init(|| 12345);
+/// assert_eq!(value, &12345);
+/// })
+/// .join()
+/// .unwrap();
///
-/// let value: Option<&String> = CELL.get();
-/// assert!(value.is_some());
-/// assert_eq!(value.unwrap().as_str(), "Hello, World!");
+/// // `OnceLock` now contains the value.
+/// assert_eq!(
+/// CELL.get(),
+/// Some(&12345),
+/// );
/// ```
#[stable(feature = "once_cell", since = "1.70.0")]
pub struct OnceLock<T> {
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index ac7c800ff..5d8967bfb 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -532,7 +532,7 @@ impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> {
}
#[stable(feature = "std_debug", since = "1.16.0")]
-impl<T: fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> {
+impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
@@ -546,7 +546,7 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'_, T> {
}
#[stable(feature = "std_debug", since = "1.16.0")]
-impl<T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> {
+impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs
index d58aa6c27..b7357460f 100644
--- a/library/std/src/sys/common/alloc.rs
+++ b/library/std/src/sys/common/alloc.rs
@@ -14,7 +14,6 @@ use crate::ptr;
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "sparc",
- target_arch = "asmjs",
target_arch = "wasm32",
target_arch = "hexagon",
all(target_arch = "riscv32", not(target_os = "espidf")),
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index 159ffe7ac..88420bd36 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -53,6 +53,9 @@ cfg_if::cfg_if! {
} else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
mod sgx;
pub use self::sgx::*;
+ } else if #[cfg(target_os = "teeos")] {
+ mod teeos;
+ pub use self::teeos::*;
} else {
mod unsupported;
pub use self::unsupported::*;
diff --git a/library/std/src/sys/personality/mod.rs b/library/std/src/sys/personality/mod.rs
index 386a399f5..d37b8ce63 100644
--- a/library/std/src/sys/personality/mod.rs
+++ b/library/std/src/sys/personality/mod.rs
@@ -12,7 +12,7 @@
mod dwarf;
-#[cfg(not(test))]
+#[cfg(not(any(test, doctest)))]
cfg_if::cfg_if! {
if #[cfg(target_os = "emscripten")] {
mod emcc;
@@ -28,6 +28,7 @@ cfg_if::cfg_if! {
} else if #[cfg(any(
all(target_family = "windows", target_env = "gnu"),
target_os = "psp",
+ target_os = "xous",
target_os = "solid_asp3",
all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re")),
all(target_vendor = "fortanix", target_env = "sgx"),
diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs
index 1eae0fc06..a768e2406 100644
--- a/library/std/src/sys/solid/net.rs
+++ b/library/std/src/sys/solid/net.rs
@@ -5,9 +5,10 @@ use crate::{
io::{self, BorrowedBuf, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut},
mem,
net::{Shutdown, SocketAddr},
+ os::solid::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd},
ptr, str,
sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr},
- sys_common::{AsInner, FromInner, IntoInner},
+ sys_common::{FromInner, IntoInner},
time::Duration,
};
@@ -28,102 +29,6 @@ const fn max_iov() -> usize {
1024
}
-/// A file descriptor.
-#[rustc_layout_scalar_valid_range_start(0)]
-// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
-// 32-bit c_int. Below is -2, in two's complement, but that only works out
-// because c_int is 32 bits.
-#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
-struct FileDesc {
- fd: c_int,
-}
-
-impl FileDesc {
- #[inline]
- fn new(fd: c_int) -> FileDesc {
- assert_ne!(fd, -1i32);
- // Safety: we just asserted that the value is in the valid range and
- // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
- unsafe { FileDesc { fd } }
- }
-
- #[inline]
- fn raw(&self) -> c_int {
- self.fd
- }
-
- /// Extracts the actual file descriptor without closing it.
- #[inline]
- fn into_raw(self) -> c_int {
- let fd = self.fd;
- mem::forget(self);
- fd
- }
-
- fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
- let ret = cvt(unsafe {
- netc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
- })?;
- Ok(ret as usize)
- }
-
- fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- let ret = cvt(unsafe {
- netc::readv(
- self.fd,
- bufs.as_ptr() as *const netc::iovec,
- cmp::min(bufs.len(), max_iov()) as c_int,
- )
- })?;
- Ok(ret as usize)
- }
-
- #[inline]
- fn is_read_vectored(&self) -> bool {
- true
- }
-
- fn write(&self, buf: &[u8]) -> io::Result<usize> {
- let ret = cvt(unsafe {
- netc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
- })?;
- Ok(ret as usize)
- }
-
- fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- let ret = cvt(unsafe {
- netc::writev(
- self.fd,
- bufs.as_ptr() as *const netc::iovec,
- cmp::min(bufs.len(), max_iov()) as c_int,
- )
- })?;
- Ok(ret as usize)
- }
-
- #[inline]
- fn is_write_vectored(&self) -> bool {
- true
- }
-
- fn duplicate(&self) -> io::Result<FileDesc> {
- cvt(unsafe { netc::dup(self.fd) }).map(Self::new)
- }
-}
-
-impl AsInner<c_int> for FileDesc {
- #[inline]
- fn as_inner(&self) -> &c_int {
- &self.fd
- }
-}
-
-impl Drop for FileDesc {
- fn drop(&mut self) {
- unsafe { netc::close(self.fd) };
- }
-}
-
#[doc(hidden)]
pub trait IsMinusOne {
fn is_minus_one(&self) -> bool;
@@ -212,7 +117,7 @@ pub(super) fn decode_error_kind(er: abi::ER) -> ErrorKind {
pub fn init() {}
-pub struct Socket(FileDesc);
+pub struct Socket(OwnedFd);
impl Socket {
pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
@@ -226,16 +131,13 @@ impl Socket {
pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
unsafe {
let fd = cvt(netc::socket(fam, ty, 0))?;
- let fd = FileDesc::new(fd);
- let socket = Socket(fd);
-
- Ok(socket)
+ Ok(Self::from_raw_fd(fd))
}
}
pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
let (addr, len) = addr.into_inner();
- cvt(unsafe { netc::connect(self.0.raw(), addr.as_ptr(), len) })?;
+ cvt(unsafe { netc::connect(self.as_raw_fd(), addr.as_ptr(), len) })?;
Ok(())
}
@@ -264,14 +166,14 @@ impl Socket {
timeout.tv_usec = 1;
}
- let fds = netc::fd_set { num_fds: 1, fds: [self.0.raw()] };
+ let fds = netc::fd_set { num_fds: 1, fds: [self.as_raw_fd()] };
let mut writefds = fds;
let mut errorfds = fds;
let n = unsafe {
cvt(netc::select(
- self.0.raw() + 1,
+ self.as_raw_fd() + 1,
ptr::null_mut(),
&mut writefds,
&mut errorfds,
@@ -294,18 +196,17 @@ impl Socket {
}
pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket> {
- let fd = cvt_r(|| unsafe { netc::accept(self.0.raw(), storage, len) })?;
- let fd = FileDesc::new(fd);
- Ok(Socket(fd))
+ let fd = cvt_r(|| unsafe { netc::accept(self.as_raw_fd(), storage, len) })?;
+ unsafe { Ok(Self::from_raw_fd(fd)) }
}
pub fn duplicate(&self) -> io::Result<Socket> {
- self.0.duplicate().map(Socket)
+ Ok(Self(self.0.try_clone()?))
}
fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> {
let ret = cvt(unsafe {
- netc::recv(self.0.raw(), buf.as_mut().as_mut_ptr().cast(), buf.capacity(), flags)
+ netc::recv(self.as_raw_fd(), buf.as_mut().as_mut_ptr().cast(), buf.capacity(), flags)
})?;
unsafe {
buf.advance(ret as usize);
@@ -330,12 +231,19 @@ impl Socket {
}
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- self.0.read_vectored(bufs)
+ let ret = cvt(unsafe {
+ netc::readv(
+ self.as_raw_fd(),
+ bufs.as_ptr() as *const netc::iovec,
+ cmp::min(bufs.len(), max_iov()) as c_int,
+ )
+ })?;
+ Ok(ret as usize)
}
#[inline]
pub fn is_read_vectored(&self) -> bool {
- self.0.is_read_vectored()
+ true
}
fn recv_from_with_flags(
@@ -348,7 +256,7 @@ impl Socket {
let n = cvt(unsafe {
netc::recvfrom(
- self.0.raw(),
+ self.as_raw_fd(),
buf.as_mut_ptr() as *mut c_void,
buf.len(),
flags,
@@ -368,16 +276,30 @@ impl Socket {
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
- self.0.write(buf)
+ let ret = cvt(unsafe {
+ netc::write(
+ self.as_raw_fd(),
+ buf.as_ptr() as *const c_void,
+ cmp::min(buf.len(), READ_LIMIT),
+ )
+ })?;
+ Ok(ret as usize)
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- self.0.write_vectored(bufs)
+ let ret = cvt(unsafe {
+ netc::writev(
+ self.as_raw_fd(),
+ bufs.as_ptr() as *const netc::iovec,
+ cmp::min(bufs.len(), max_iov()) as c_int,
+ )
+ })?;
+ Ok(ret as usize)
}
#[inline]
pub fn is_write_vectored(&self) -> bool {
- self.0.is_write_vectored()
+ true
}
pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> {
@@ -423,7 +345,7 @@ impl Socket {
Shutdown::Read => netc::SHUT_RD,
Shutdown::Both => netc::SHUT_RDWR,
};
- cvt(unsafe { netc::shutdown(self.0.raw(), how) })?;
+ cvt(unsafe { netc::shutdown(self.as_raw_fd(), how) })?;
Ok(())
}
@@ -454,7 +376,7 @@ impl Socket {
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let mut nonblocking = nonblocking as c_int;
cvt(unsafe {
- netc::ioctl(*self.as_inner(), netc::FIONBIO, (&mut nonblocking) as *mut c_int as _)
+ netc::ioctl(self.as_raw_fd(), netc::FIONBIO, (&mut nonblocking) as *mut c_int as _)
})
.map(drop)
}
@@ -466,25 +388,48 @@ impl Socket {
// This method is used by sys_common code to abstract over targets.
pub fn as_raw(&self) -> c_int {
- *self.as_inner()
+ self.as_raw_fd()
}
}
-impl AsInner<c_int> for Socket {
+impl FromInner<OwnedFd> for Socket {
#[inline]
- fn as_inner(&self) -> &c_int {
- self.0.as_inner()
+ fn from_inner(sock: OwnedFd) -> Socket {
+ Socket(sock)
}
}
-impl FromInner<c_int> for Socket {
- fn from_inner(fd: c_int) -> Socket {
- Socket(FileDesc::new(fd))
+impl IntoInner<OwnedFd> for Socket {
+ #[inline]
+ fn into_inner(self) -> OwnedFd {
+ self.0
}
}
-impl IntoInner<c_int> for Socket {
- fn into_inner(self) -> c_int {
- self.0.into_raw()
+impl AsFd for Socket {
+ #[inline]
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.0.as_fd()
+ }
+}
+
+impl AsRawFd for Socket {
+ #[inline]
+ fn as_raw_fd(&self) -> c_int {
+ self.0.as_raw_fd()
+ }
+}
+
+impl FromRawFd for Socket {
+ #[inline]
+ unsafe fn from_raw_fd(fd: c_int) -> Socket {
+ unsafe { Self(FromRawFd::from_raw_fd(fd)) }
+ }
+}
+
+impl IntoRawFd for Socket {
+ #[inline]
+ fn into_raw_fd(self) -> c_int {
+ self.0.into_raw_fd()
}
}
diff --git a/library/std/src/sys/teeos/alloc.rs b/library/std/src/sys/teeos/alloc.rs
new file mode 100644
index 000000000..e236819aa
--- /dev/null
+++ b/library/std/src/sys/teeos/alloc.rs
@@ -0,0 +1,57 @@
+use crate::alloc::{GlobalAlloc, Layout, System};
+use crate::ptr;
+use crate::sys::common::alloc::{realloc_fallback, MIN_ALIGN};
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ // jemalloc provides alignment less than MIN_ALIGN for small allocations.
+ // So only rely on MIN_ALIGN if size >= align.
+ // Also see <https://github.com/rust-lang/rust/issues/45955> and
+ // <https://github.com/rust-lang/rust/issues/62251#issuecomment-507580914>.
+ if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+ libc::malloc(layout.size()) as *mut u8
+ } else {
+ aligned_malloc(&layout)
+ }
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ // See the comment above in `alloc` for why this check looks the way it does.
+ if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+ libc::calloc(layout.size(), 1) as *mut u8
+ } else {
+ let ptr = self.alloc(layout);
+ if !ptr.is_null() {
+ ptr::write_bytes(ptr, 0, layout.size());
+ }
+ ptr
+ }
+ }
+
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+ libc::free(ptr as *mut libc::c_void)
+ }
+
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
+ libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
+ } else {
+ realloc_fallback(self, ptr, layout, new_size)
+ }
+ }
+}
+
+#[inline]
+unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+ let mut out = ptr::null_mut();
+ // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
+ // Since these are all powers of 2, we can just use max.
+ let align = layout.align().max(crate::mem::size_of::<usize>());
+ let ret = libc::posix_memalign(&mut out, align, layout.size());
+ if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
+}
diff --git a/library/std/src/sys/teeos/locks/condvar.rs b/library/std/src/sys/teeos/locks/condvar.rs
new file mode 100644
index 000000000..c08e8145b
--- /dev/null
+++ b/library/std/src/sys/teeos/locks/condvar.rs
@@ -0,0 +1,100 @@
+use crate::cell::UnsafeCell;
+use crate::ptr;
+use crate::sync::atomic::{AtomicPtr, Ordering::Relaxed};
+use crate::sys::locks::mutex::{self, Mutex};
+use crate::sys::time::TIMESPEC_MAX;
+use crate::sys_common::lazy_box::{LazyBox, LazyInit};
+use crate::time::Duration;
+
+extern "C" {
+ pub fn pthread_cond_timedwait(
+ cond: *mut libc::pthread_cond_t,
+ lock: *mut libc::pthread_mutex_t,
+ adstime: *const libc::timespec,
+ ) -> libc::c_int;
+}
+
+struct AllocatedCondvar(UnsafeCell<libc::pthread_cond_t>);
+
+pub struct Condvar {
+ inner: LazyBox<AllocatedCondvar>,
+ mutex: AtomicPtr<libc::pthread_mutex_t>,
+}
+
+#[inline]
+fn raw(c: &Condvar) -> *mut libc::pthread_cond_t {
+ c.inner.0.get()
+}
+
+unsafe impl Send for AllocatedCondvar {}
+unsafe impl Sync for AllocatedCondvar {}
+
+impl LazyInit for AllocatedCondvar {
+ fn init() -> Box<Self> {
+ let condvar = Box::new(AllocatedCondvar(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)));
+
+ let r = unsafe { libc::pthread_cond_init(condvar.0.get(), crate::ptr::null()) };
+ assert_eq!(r, 0);
+
+ condvar
+ }
+}
+
+impl Drop for AllocatedCondvar {
+ #[inline]
+ fn drop(&mut self) {
+ let r = unsafe { libc::pthread_cond_destroy(self.0.get()) };
+ debug_assert_eq!(r, 0);
+ }
+}
+
+impl Condvar {
+ pub const fn new() -> Condvar {
+ Condvar { inner: LazyBox::new(), mutex: AtomicPtr::new(ptr::null_mut()) }
+ }
+
+ #[inline]
+ fn verify(&self, mutex: *mut libc::pthread_mutex_t) {
+ match self.mutex.compare_exchange(ptr::null_mut(), mutex, Relaxed, Relaxed) {
+ Ok(_) => {} // Stored the address
+ Err(n) if n == mutex => {} // Lost a race to store the same address
+ _ => panic!("attempted to use a condition variable with two mutexes"),
+ }
+ }
+
+ #[inline]
+ pub fn notify_one(&self) {
+ let r = unsafe { libc::pthread_cond_signal(raw(self)) };
+ debug_assert_eq!(r, 0);
+ }
+
+ #[inline]
+ pub fn notify_all(&self) {
+ let r = unsafe { libc::pthread_cond_broadcast(raw(self)) };
+ debug_assert_eq!(r, 0);
+ }
+
+ #[inline]
+ pub unsafe fn wait(&self, mutex: &Mutex) {
+ let mutex = mutex::raw(mutex);
+ self.verify(mutex);
+ let r = libc::pthread_cond_wait(raw(self), mutex);
+ debug_assert_eq!(r, 0);
+ }
+
+ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+ use crate::sys::time::Timespec;
+
+ let mutex = mutex::raw(mutex);
+ self.verify(mutex);
+
+ let timeout = Timespec::now(libc::CLOCK_MONOTONIC)
+ .checked_add_duration(&dur)
+ .and_then(|t| t.to_timespec())
+ .unwrap_or(TIMESPEC_MAX);
+
+ let r = pthread_cond_timedwait(raw(self), mutex, &timeout);
+ assert!(r == libc::ETIMEDOUT || r == 0);
+ r == 0
+ }
+}
diff --git a/library/std/src/sys/teeos/locks/mod.rs b/library/std/src/sys/teeos/locks/mod.rs
new file mode 100644
index 000000000..c58e9c7fd
--- /dev/null
+++ b/library/std/src/sys/teeos/locks/mod.rs
@@ -0,0 +1,8 @@
+pub mod condvar;
+#[path = "../../unix/locks/pthread_mutex.rs"]
+pub mod mutex;
+pub mod rwlock;
+
+pub(crate) use condvar::Condvar;
+pub(crate) use mutex::Mutex;
+pub(crate) use rwlock::RwLock;
diff --git a/library/std/src/sys/teeos/locks/rwlock.rs b/library/std/src/sys/teeos/locks/rwlock.rs
new file mode 100644
index 000000000..27cdb8878
--- /dev/null
+++ b/library/std/src/sys/teeos/locks/rwlock.rs
@@ -0,0 +1,44 @@
+use crate::sys::locks::mutex::Mutex;
+
+/// we do not supported rwlock, so use mutex to simulate rwlock.
+/// it's useful because so many code in std will use rwlock.
+pub struct RwLock {
+ inner: Mutex,
+}
+
+impl RwLock {
+ #[inline]
+ pub const fn new() -> RwLock {
+ RwLock { inner: Mutex::new() }
+ }
+
+ #[inline]
+ pub fn read(&self) {
+ unsafe { self.inner.lock() };
+ }
+
+ #[inline]
+ pub fn try_read(&self) -> bool {
+ unsafe { self.inner.try_lock() }
+ }
+
+ #[inline]
+ pub fn write(&self) {
+ unsafe { self.inner.lock() };
+ }
+
+ #[inline]
+ pub unsafe fn try_write(&self) -> bool {
+ unsafe { self.inner.try_lock() }
+ }
+
+ #[inline]
+ pub unsafe fn read_unlock(&self) {
+ unsafe { self.inner.unlock() };
+ }
+
+ #[inline]
+ pub unsafe fn write_unlock(&self) {
+ unsafe { self.inner.unlock() };
+ }
+}
diff --git a/library/std/src/sys/teeos/mod.rs b/library/std/src/sys/teeos/mod.rs
new file mode 100644
index 000000000..ed8c54b2c
--- /dev/null
+++ b/library/std/src/sys/teeos/mod.rs
@@ -0,0 +1,167 @@
+//! System bindings for the Teeos platform
+//!
+//! This module contains the facade (aka platform-specific) implementations of
+//! OS level functionality for Teeos.
+#![allow(unsafe_op_in_unsafe_fn)]
+#![allow(unused_variables)]
+#![allow(dead_code)]
+
+pub use self::rand::hashmap_random_keys;
+
+pub mod alloc;
+#[path = "../unsupported/args.rs"]
+pub mod args;
+#[path = "../unix/cmath.rs"]
+pub mod cmath;
+#[path = "../unsupported/env.rs"]
+pub mod env;
+pub mod locks;
+//pub mod fd;
+#[path = "../unsupported/fs.rs"]
+pub mod fs;
+#[path = "../unsupported/io.rs"]
+pub mod io;
+#[path = "../unix/memchr.rs"]
+pub mod memchr;
+pub mod net;
+#[path = "../unsupported/once.rs"]
+pub mod once;
+pub mod os;
+#[path = "../unix/os_str.rs"]
+pub mod os_str;
+#[path = "../unix/path.rs"]
+pub mod path;
+#[path = "../unsupported/pipe.rs"]
+pub mod pipe;
+#[path = "../unsupported/process.rs"]
+pub mod process;
+mod rand;
+pub mod stdio;
+pub mod thread;
+pub mod thread_local_dtor;
+#[path = "../unix/thread_local_key.rs"]
+pub mod thread_local_key;
+#[path = "../unsupported/thread_parking.rs"]
+pub mod thread_parking;
+#[allow(non_upper_case_globals)]
+#[path = "../unix/time.rs"]
+pub mod time;
+
+use crate::io::ErrorKind;
+
+pub fn abort_internal() -> ! {
+ unsafe { libc::abort() }
+}
+
+// Trusted Applications are loaded as dynamic libraries on Teeos,
+// so this should never be called.
+pub fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {}
+
+// SAFETY: must be called only once during runtime cleanup.
+// this is not guaranteed to run, for example when the program aborts.
+pub unsafe fn cleanup() {
+ unimplemented!()
+ // We do NOT have stack overflow handler, because TEE OS will kill TA when it happens.
+ // So cleanup is commented
+ // stack_overflow::cleanup();
+}
+
+#[inline]
+pub(crate) fn is_interrupted(errno: i32) -> bool {
+ errno == libc::EINTR
+}
+
+// Note: code below is 1:1 copied from unix/mod.rs
+pub fn decode_error_kind(errno: i32) -> ErrorKind {
+ use ErrorKind::*;
+ match errno as libc::c_int {
+ libc::E2BIG => ArgumentListTooLong,
+ libc::EADDRINUSE => AddrInUse,
+ libc::EADDRNOTAVAIL => AddrNotAvailable,
+ libc::EBUSY => ResourceBusy,
+ libc::ECONNABORTED => ConnectionAborted,
+ libc::ECONNREFUSED => ConnectionRefused,
+ libc::ECONNRESET => ConnectionReset,
+ libc::EDEADLK => Deadlock,
+ libc::EDQUOT => FilesystemQuotaExceeded,
+ libc::EEXIST => AlreadyExists,
+ libc::EFBIG => FileTooLarge,
+ libc::EHOSTUNREACH => HostUnreachable,
+ libc::EINTR => Interrupted,
+ libc::EINVAL => InvalidInput,
+ libc::EISDIR => IsADirectory,
+ libc::ELOOP => FilesystemLoop,
+ libc::ENOENT => NotFound,
+ libc::ENOMEM => OutOfMemory,
+ libc::ENOSPC => StorageFull,
+ libc::ENOSYS => Unsupported,
+ libc::EMLINK => TooManyLinks,
+ libc::ENAMETOOLONG => InvalidFilename,
+ libc::ENETDOWN => NetworkDown,
+ libc::ENETUNREACH => NetworkUnreachable,
+ libc::ENOTCONN => NotConnected,
+ libc::ENOTDIR => NotADirectory,
+ libc::ENOTEMPTY => DirectoryNotEmpty,
+ libc::EPIPE => BrokenPipe,
+ libc::EROFS => ReadOnlyFilesystem,
+ libc::ESPIPE => NotSeekable,
+ libc::ESTALE => StaleNetworkFileHandle,
+ libc::ETIMEDOUT => TimedOut,
+ libc::ETXTBSY => ExecutableFileBusy,
+ libc::EXDEV => CrossesDevices,
+
+ libc::EACCES | libc::EPERM => PermissionDenied,
+
+ // These two constants can have the same value on some systems,
+ // but different values on others, so we can't use a match
+ // clause
+ x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock,
+
+ _ => Uncategorized,
+ }
+}
+
+#[doc(hidden)]
+pub trait IsMinusOne {
+ fn is_minus_one(&self) -> bool;
+}
+
+macro_rules! impl_is_minus_one {
+ ($($t:ident)*) => ($(impl IsMinusOne for $t {
+ fn is_minus_one(&self) -> bool {
+ *self == -1
+ }
+ })*)
+}
+
+impl_is_minus_one! { i8 i16 i32 i64 isize }
+
+pub fn cvt<T: IsMinusOne>(t: T) -> crate::io::Result<T> {
+ if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) }
+}
+
+pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
+where
+ T: IsMinusOne,
+ F: FnMut() -> T,
+{
+ loop {
+ match cvt(f()) {
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ other => return other,
+ }
+ }
+}
+
+pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> {
+ if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) }
+}
+
+use crate::io as std_io;
+pub fn unsupported<T>() -> std_io::Result<T> {
+ Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> std_io::Error {
+ std_io::Error::new(std_io::ErrorKind::Unsupported, "operation not supported on this platform")
+}
diff --git a/library/std/src/sys/teeos/net.rs b/library/std/src/sys/teeos/net.rs
new file mode 100644
index 000000000..0df681dbf
--- /dev/null
+++ b/library/std/src/sys/teeos/net.rs
@@ -0,0 +1,372 @@
+use crate::fmt;
+use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
+use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
+use crate::sys::unsupported;
+use crate::time::Duration;
+
+pub struct TcpStream(!);
+
+impl TcpStream {
+ pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+ unsupported()
+ }
+
+ pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+ unsupported()
+ }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ self.0
+ }
+
+ pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+ self.0
+ }
+
+ pub fn read_buf(&self, _buf: BorrowedCursor<'_>) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ self.0
+ }
+
+ pub fn is_read_vectored(&self) -> bool {
+ self.0
+ }
+
+ pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+ self.0
+ }
+
+ pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
+ self.0
+ }
+
+ pub fn is_write_vectored(&self) -> bool {
+ self.0
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ self.0
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ self.0
+ }
+
+ pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpStream> {
+ self.0
+ }
+
+ pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn linger(&self) -> io::Result<Option<Duration>> {
+ self.0
+ }
+
+ pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ self.0
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.0
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ self.0
+ }
+}
+
+impl fmt::Debug for TcpStream {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0
+ }
+}
+
+pub struct TcpListener(!);
+
+impl TcpListener {
+ pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+ unsupported()
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ self.0
+ }
+
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ self.0
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpListener> {
+ self.0
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.0
+ }
+
+ pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn only_v6(&self) -> io::Result<bool> {
+ self.0
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ self.0
+ }
+}
+
+impl fmt::Debug for TcpListener {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0
+ }
+}
+
+pub struct UdpSocket(!);
+
+impl UdpSocket {
+ pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+ unsupported()
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ self.0
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ self.0
+ }
+
+ pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.0
+ }
+
+ pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.0
+ }
+
+ pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+ self.0
+ }
+
+ pub fn duplicate(&self) -> io::Result<UdpSocket> {
+ self.0
+ }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ self.0
+ }
+
+ pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn broadcast(&self) -> io::Result<bool> {
+ self.0
+ }
+
+ pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ self.0
+ }
+
+ pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ self.0
+ }
+
+ pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ self.0
+ }
+
+ pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ self.0
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ self.0
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ self.0
+ }
+
+ pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+ self.0
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ self.0
+ }
+
+ pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+ self.0
+ }
+
+ pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+ self.0
+ }
+}
+
+impl fmt::Debug for UdpSocket {
+ fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0
+ }
+}
+
+pub struct LookupHost(!);
+
+impl LookupHost {
+ pub fn port(&self) -> u16 {
+ self.0
+ }
+}
+
+impl Iterator for LookupHost {
+ type Item = SocketAddr;
+ fn next(&mut self) -> Option<SocketAddr> {
+ self.0
+ }
+}
+
+impl TryFrom<&str> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(_v: &str) -> io::Result<LookupHost> {
+ unsupported()
+ }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
+ unsupported()
+ }
+}
+
+#[allow(nonstandard_style)]
+pub mod netc {
+ pub const AF_INET: u8 = 0;
+ pub const AF_INET6: u8 = 1;
+ pub type sa_family_t = u8;
+
+ #[derive(Copy, Clone)]
+ pub struct in_addr {
+ pub s_addr: u32,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in {
+ pub sin_family: sa_family_t,
+ pub sin_port: u16,
+ pub sin_addr: in_addr,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct in6_addr {
+ pub s6_addr: [u8; 16],
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in6 {
+ pub sin6_family: sa_family_t,
+ pub sin6_port: u16,
+ pub sin6_addr: in6_addr,
+ pub sin6_flowinfo: u32,
+ pub sin6_scope_id: u32,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr {}
+}
+
+pub type Socket = UdpSocket;
diff --git a/library/std/src/sys/teeos/os.rs b/library/std/src/sys/teeos/os.rs
new file mode 100644
index 000000000..e54a92f01
--- /dev/null
+++ b/library/std/src/sys/teeos/os.rs
@@ -0,0 +1,134 @@
+//! Implementation of `std::os` functionality for teeos
+
+use core::marker::PhantomData;
+
+use crate::error::Error as StdError;
+use crate::ffi::{OsStr, OsString};
+use crate::fmt;
+use crate::io;
+use crate::path;
+use crate::path::PathBuf;
+
+use super::unsupported;
+
+pub fn errno() -> i32 {
+ unsafe { (*libc::__errno_location()) as i32 }
+}
+
+// Hardcoded to return 4096, since `sysconf` is only implemented as a stub.
+pub fn page_size() -> usize {
+ // unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };
+ 4096
+}
+
+// Everything below are stubs and copied from unsupported.rs
+
+pub fn error_string(_errno: i32) -> String {
+ "error string unimplemented".to_string()
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub struct SplitPaths<'a>(!, PhantomData<&'a ()>);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
+ panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> {
+ self.0
+ }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+where
+ I: Iterator<Item = T>,
+ T: AsRef<OsStr>,
+{
+ Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "not supported on this platform yet".fmt(f)
+ }
+}
+
+impl StdError for JoinPathsError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ "not supported on this platform yet"
+ }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub struct Env(!);
+
+impl Env {
+ // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
+ pub fn str_debug(&self) -> impl fmt::Debug + '_ {
+ let Self(inner) = self;
+ match *inner {}
+ }
+}
+
+impl fmt::Debug for Env {
+ fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let Self(inner) = self;
+ match *inner {}
+ }
+}
+
+impl Iterator for Env {
+ type Item = (OsString, OsString);
+ fn next(&mut self) -> Option<(OsString, OsString)> {
+ let Self(inner) = self;
+ match *inner {}
+ }
+}
+
+pub fn env() -> Env {
+ panic!("not supported on this platform")
+}
+
+pub fn getenv(_: &OsStr) -> Option<OsString> {
+ None
+}
+
+pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
+ Err(io::Error::new(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
+}
+
+pub fn unsetenv(_: &OsStr) -> io::Result<()> {
+ Err(io::Error::new(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
+}
+
+pub fn temp_dir() -> PathBuf {
+ panic!("no filesystem on this platform")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ None
+}
+
+pub fn exit(_code: i32) -> ! {
+ panic!("TA should not call `exit`")
+}
+
+pub fn getpid() -> u32 {
+ panic!("no pids on this platform")
+}
diff --git a/library/std/src/sys/teeos/rand.rs b/library/std/src/sys/teeos/rand.rs
new file mode 100644
index 000000000..b45c3bb40
--- /dev/null
+++ b/library/std/src/sys/teeos/rand.rs
@@ -0,0 +1,21 @@
+pub fn hashmap_random_keys() -> (u64, u64) {
+ const KEY_LEN: usize = core::mem::size_of::<u64>();
+
+ let mut v = [0u8; KEY_LEN * 2];
+ imp::fill_bytes(&mut v);
+
+ let key1 = v[0..KEY_LEN].try_into().unwrap();
+ let key2 = v[KEY_LEN..].try_into().unwrap();
+
+ (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2))
+}
+
+mod imp {
+ extern "C" {
+ fn TEE_GenerateRandom(randomBuffer: *mut core::ffi::c_void, randomBufferLen: libc::size_t);
+ }
+
+ pub fn fill_bytes(v: &mut [u8]) {
+ unsafe { TEE_GenerateRandom(v.as_mut_ptr() as _, v.len() * crate::mem::size_of::<u8>()) }
+ }
+}
diff --git a/library/std/src/sys/teeos/stdio.rs b/library/std/src/sys/teeos/stdio.rs
new file mode 100644
index 000000000..9ca04f292
--- /dev/null
+++ b/library/std/src/sys/teeos/stdio.rs
@@ -0,0 +1,88 @@
+#![deny(unsafe_op_in_unsafe_fn)]
+
+use crate::io;
+use core::arch::asm;
+
+pub struct Stdin;
+pub struct Stdout;
+pub struct Stderr;
+
+const KCALL_DEBUG_CMD_PUT_BYTES: i64 = 2;
+
+unsafe fn debug_call(cap_ref: u64, call_no: i64, arg1: u64, arg2: u64) -> i32 {
+ let ret: u64;
+ unsafe {
+ asm!(
+ "svc #99",
+ inout("x0") cap_ref => ret,
+ in("x1") call_no,
+ in("x2") arg1,
+ in("x3") arg2,
+ );
+ }
+
+ ret as i32
+}
+
+fn print_buf(s: &[u8]) -> io::Result<usize> {
+ // Corresponds to `HM_DEBUG_PUT_BYTES_LIMIT`.
+ const MAX_LEN: usize = 512;
+ let len = if s.len() > MAX_LEN { MAX_LEN } else { s.len() };
+ let result = unsafe { debug_call(0, KCALL_DEBUG_CMD_PUT_BYTES, s.as_ptr() as u64, len as u64) };
+
+ if result == 0 { Ok(len) } else { Err(io::Error::from(io::ErrorKind::InvalidInput)) }
+}
+
+impl Stdin {
+ pub const fn new() -> Stdin {
+ Stdin
+ }
+}
+
+impl io::Read for Stdin {
+ fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
+ Ok(0)
+ }
+}
+
+impl Stdout {
+ pub const fn new() -> Stdout {
+ Stdout
+ }
+}
+
+impl io::Write for Stdout {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ print_buf(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl Stderr {
+ pub const fn new() -> Stderr {
+ Stderr
+ }
+}
+
+impl io::Write for Stderr {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ print_buf(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+pub const STDIN_BUF_SIZE: usize = 0;
+
+pub fn is_ebadf(err: &io::Error) -> bool {
+ err.raw_os_error() == Some(libc::EBADF as i32)
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+ Some(Stderr::new())
+}
diff --git a/library/std/src/sys/teeos/thread.rs b/library/std/src/sys/teeos/thread.rs
new file mode 100644
index 000000000..155f333f9
--- /dev/null
+++ b/library/std/src/sys/teeos/thread.rs
@@ -0,0 +1,164 @@
+use core::convert::TryInto;
+
+use crate::cmp;
+use crate::ffi::CStr;
+use crate::io;
+use crate::mem;
+use crate::num::NonZeroUsize;
+use crate::ptr;
+use crate::sys::os;
+use crate::time::Duration;
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 8 * 1024;
+
+pub struct Thread {
+ id: libc::pthread_t,
+}
+
+// Some platforms may have pthread_t as a pointer in which case we still want
+// a thread to be Send/Sync
+unsafe impl Send for Thread {}
+unsafe impl Sync for Thread {}
+
+extern "C" {
+ pub fn TEE_Wait(timeout: u32) -> u32;
+}
+
+impl Thread {
+ // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+ let p = Box::into_raw(Box::new(p));
+ let mut native: libc::pthread_t = mem::zeroed();
+ let mut attr: libc::pthread_attr_t = mem::zeroed();
+ assert_eq!(libc::pthread_attr_init(&mut attr), 0);
+ assert_eq!(
+ libc::pthread_attr_settee(
+ &mut attr,
+ libc::TEESMP_THREAD_ATTR_CA_INHERIT,
+ libc::TEESMP_THREAD_ATTR_TASK_ID_INHERIT,
+ libc::TEESMP_THREAD_ATTR_HAS_SHADOW,
+ ),
+ 0,
+ );
+
+ let stack_size = cmp::max(stack, min_stack_size(&attr));
+
+ match libc::pthread_attr_setstacksize(&mut attr, stack_size) {
+ 0 => {}
+ n => {
+ assert_eq!(n, libc::EINVAL);
+ // EINVAL means |stack_size| is either too small or not a
+ // multiple of the system page size. Because it's definitely
+ // >= PTHREAD_STACK_MIN, it must be an alignment issue.
+ // Round up to the nearest page and try again.
+ let page_size = os::page_size();
+ let stack_size =
+ (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1);
+ assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0);
+ }
+ };
+
+ let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);
+ // Note: if the thread creation fails and this assert fails, then p will
+ // be leaked. However, an alternative design could cause double-free
+ // which is clearly worse.
+ assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
+
+ return if ret != 0 {
+ // The thread failed to start and as a result p was not consumed. Therefore, it is
+ // safe to reconstruct the box so that it gets deallocated.
+ drop(Box::from_raw(p));
+ Err(io::Error::from_raw_os_error(ret))
+ } else {
+ // The new thread will start running earliest after the next yield.
+ // We add a yield here, so that the user does not have to.
+ Thread::yield_now();
+ Ok(Thread { id: native })
+ };
+
+ extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
+ unsafe {
+ // Next, set up our stack overflow handler which may get triggered if we run
+ // out of stack.
+ // this is not necessary in TEE.
+ //let _handler = stack_overflow::Handler::new();
+ // Finally, let's run some code.
+ Box::from_raw(main as *mut Box<dyn FnOnce()>)();
+ }
+ ptr::null_mut()
+ }
+ }
+
+ pub fn yield_now() {
+ let ret = unsafe { libc::sched_yield() };
+ debug_assert_eq!(ret, 0);
+ }
+
+ /// This does not do anything on teeos
+ pub fn set_name(_name: &CStr) {
+ // Both pthread_setname_np and prctl are not available to the TA,
+ // so we can't implement this currently. If the need arises please
+ // contact the teeos rustzone team.
+ }
+
+ /// only main thread could wait for sometime in teeos
+ pub fn sleep(dur: Duration) {
+ let sleep_millis = dur.as_millis();
+ let final_sleep: u32 =
+ if sleep_millis >= u32::MAX as u128 { u32::MAX } else { sleep_millis as u32 };
+ unsafe {
+ let _ = TEE_Wait(final_sleep);
+ }
+ }
+
+ /// must join, because no pthread_detach supported
+ pub fn join(self) {
+ unsafe {
+ let ret = libc::pthread_join(self.id, ptr::null_mut());
+ mem::forget(self);
+ assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret));
+ }
+ }
+
+ pub fn id(&self) -> libc::pthread_t {
+ self.id
+ }
+
+ pub fn into_id(self) -> libc::pthread_t {
+ let id = self.id;
+ mem::forget(self);
+ id
+ }
+}
+
+impl Drop for Thread {
+ fn drop(&mut self) {
+ // we can not call detach, so just panic if thread spawn without join
+ panic!("thread must join, detach is not supported!");
+ }
+}
+
+// Note: Both `sched_getaffinity` and `sysconf` are available but not functional on
+// teeos, so this function always returns an Error!
+pub fn available_parallelism() -> io::Result<NonZeroUsize> {
+ Err(io::Error::new(
+ io::ErrorKind::NotFound,
+ "The number of hardware threads is not known for the target platform",
+ ))
+}
+
+// stub
+pub mod guard {
+ use crate::ops::Range;
+ pub type Guard = Range<usize>;
+ pub unsafe fn current() -> Option<Guard> {
+ None
+ }
+ pub unsafe fn init() -> Option<Guard> {
+ None
+ }
+}
+
+fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
+ libc::PTHREAD_STACK_MIN.try_into().expect("Infallible")
+}
diff --git a/library/std/src/sys/teeos/thread_local_dtor.rs b/library/std/src/sys/teeos/thread_local_dtor.rs
new file mode 100644
index 000000000..5c6bc4d67
--- /dev/null
+++ b/library/std/src/sys/teeos/thread_local_dtor.rs
@@ -0,0 +1,4 @@
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
+ use crate::sys_common::thread_local_dtor::register_dtor_fallback;
+ register_dtor_fallback(t, dtor);
+}
diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs
index 2da17fabc..9f7dcc041 100644
--- a/library/std/src/sys/unix/args.rs
+++ b/library/std/src/sys/unix/args.rs
@@ -244,13 +244,15 @@ mod imp {
let mut res = Vec::new();
unsafe {
- let process_info_sel = sel_registerName("processInfo\0".as_ptr());
- let arguments_sel = sel_registerName("arguments\0".as_ptr());
- let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
- let count_sel = sel_registerName("count\0".as_ptr());
- let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
-
- let klass = objc_getClass("NSProcessInfo\0".as_ptr());
+ let process_info_sel =
+ sel_registerName(c"processInfo".as_ptr() as *const libc::c_uchar);
+ let arguments_sel = sel_registerName(c"arguments".as_ptr() as *const libc::c_uchar);
+ let utf8_sel = sel_registerName(c"UTF8String".as_ptr() as *const libc::c_uchar);
+ let count_sel = sel_registerName(c"count".as_ptr() as *const libc::c_uchar);
+ let object_at_sel =
+ sel_registerName(c"objectAtIndex:".as_ptr() as *const libc::c_uchar);
+
+ let klass = objc_getClass(c"NSProcessInfo".as_ptr() as *const libc::c_uchar);
let info = objc_msgSend(klass, process_info_sel);
let args = objc_msgSend(info, arguments_sel);
diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs
index 3bb492fa9..3d4ba5098 100644
--- a/library/std/src/sys/unix/env.rs
+++ b/library/std/src/sys/unix/env.rs
@@ -174,17 +174,6 @@ pub mod os {
pub const EXE_EXTENSION: &str = "elf";
}
-#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))]
-pub mod os {
- pub const FAMILY: &str = "unix";
- pub const OS: &str = "emscripten";
- pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".so";
- pub const DLL_EXTENSION: &str = "so";
- pub const EXE_SUFFIX: &str = ".js";
- pub const EXE_EXTENSION: &str = "js";
-}
-
#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))]
pub mod os {
pub const FAMILY: &str = "unix";
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 40eb910fd..72e7b1b1f 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -1140,7 +1140,7 @@ impl File {
cfg_has_statx! {
if let Some(ret) = unsafe { try_statx(
fd,
- b"\0" as *const _ as *const c_char,
+ c"".as_ptr() as *const c_char,
libc::AT_EMPTY_PATH | libc::AT_STATX_SYNC_AS_STAT,
libc::STATX_ALL,
) } {
@@ -1300,13 +1300,17 @@ impl File {
pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
#[cfg(not(any(target_os = "redox", target_os = "espidf", target_os = "horizon")))]
- let to_timespec = |time: Option<SystemTime>| {
- match time {
- Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts),
- Some(time) if time > crate::sys::time::UNIX_EPOCH => Err(io::const_io_error!(io::ErrorKind::InvalidInput, "timestamp is too large to set as a file time")),
- Some(_) => Err(io::const_io_error!(io::ErrorKind::InvalidInput, "timestamp is too small to set as a file time")),
- None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }),
- }
+ let to_timespec = |time: Option<SystemTime>| match time {
+ Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts),
+ Some(time) if time > crate::sys::time::UNIX_EPOCH => Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "timestamp is too large to set as a file time"
+ )),
+ Some(_) => Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "timestamp is too small to set as a file time"
+ )),
+ None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }),
};
cfg_if::cfg_if! {
if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon"))] {
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 4b28f6feb..b5da5f870 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -1,6 +1,5 @@
#![allow(missing_docs, nonstandard_style)]
-use crate::ffi::CStr;
use crate::io::ErrorKind;
pub use self::rand::hashmap_random_keys;
@@ -75,7 +74,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
// thread-id for the main thread and so renaming the main thread will rename the
// process and we only want to enable this on platforms we've tested.
if cfg!(target_os = "macos") {
- thread::Thread::set_name(&CStr::from_bytes_with_nul_unchecked(b"main\0"));
+ thread::Thread::set_name(&c"main");
}
unsafe fn sanitize_standard_fds() {
@@ -127,7 +126,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
if pfd.revents & libc::POLLNVAL == 0 {
continue;
}
- if open64("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+ if open64(c"/dev/null".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
// If the stream is closed but we failed to reopen it, abort the
// process. Otherwise we wouldn't preserve the safety of
// operations on the corresponding Rust object Stdin, Stdout, or
@@ -157,7 +156,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
use libc::open64;
for fd in 0..3 {
if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
- if open64("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
+ if open64(c"/dev/null".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
// If the stream is closed but we failed to reopen it, abort the
// process. Otherwise we wouldn't preserve the safety of
// operations on the corresponding Rust object Stdin, Stdout, or
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index dc3c037c0..881b3a25c 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -180,7 +180,7 @@ pub fn getcwd() -> io::Result<PathBuf> {
}
#[cfg(target_os = "espidf")]
-pub fn chdir(p: &path::Path) -> io::Result<()> {
+pub fn chdir(_p: &path::Path) -> io::Result<()> {
super::unsupported::unsupported()
}
@@ -274,15 +274,19 @@ pub fn current_exe() -> io::Result<PathBuf> {
return path.canonicalize();
}
// Search PWD to infer current_exe.
- if let Some(pstr) = path.to_str() && pstr.contains("/") {
+ if let Some(pstr) = path.to_str()
+ && pstr.contains("/")
+ {
return getcwd().map(|cwd| cwd.join(path))?.canonicalize();
}
// Search PATH to infer current_exe.
if let Some(p) = getenv(OsStr::from_bytes("PATH".as_bytes())) {
for search_path in split_paths(&p) {
let pb = search_path.join(&path);
- if pb.is_file() && let Ok(metadata) = crate::fs::metadata(&pb) &&
- metadata.permissions().mode() & 0o111 != 0 {
+ if pb.is_file()
+ && let Ok(metadata) = crate::fs::metadata(&pb)
+ && metadata.permissions().mode() & 0o111 != 0
+ {
return pb.canonicalize();
}
}
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index bac32d9e6..c5f04fb8b 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -24,11 +24,11 @@ cfg_if::cfg_if! {
if #[cfg(target_os = "fuchsia")] {
// fuchsia doesn't have /dev/null
} else if #[cfg(target_os = "redox")] {
- const DEV_NULL: &str = "null:\0";
+ const DEV_NULL: &CStr = c"null:";
} else if #[cfg(target_os = "vxworks")] {
- const DEV_NULL: &str = "/null\0";
+ const DEV_NULL: &CStr = c"/null";
} else {
- const DEV_NULL: &str = "/dev/null\0";
+ const DEV_NULL: &CStr = c"/dev/null";
}
}
@@ -481,8 +481,7 @@ impl Stdio {
let mut opts = OpenOptions::new();
opts.read(readable);
opts.write(!readable);
- let path = unsafe { CStr::from_ptr(DEV_NULL.as_ptr() as *const _) };
- let fd = File::open_c(&path, &opts)?;
+ let fd = File::open_c(DEV_NULL, &opts)?;
Ok((ChildStdio::Owned(fd.into_inner()), None))
}
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 72aca4e66..ee86a5f88 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -9,6 +9,8 @@ use core::ffi::NonZero_c_int;
#[cfg(target_os = "linux")]
use crate::os::linux::process::PidFd;
+#[cfg(target_os = "linux")]
+use crate::os::unix::io::AsRawFd;
#[cfg(any(
target_os = "macos",
@@ -696,11 +698,12 @@ impl Command {
msg.msg_iov = &mut iov as *mut _ as *mut _;
msg.msg_iovlen = 1;
- msg.msg_controllen = mem::size_of_val(&cmsg.buf) as _;
- msg.msg_control = &mut cmsg.buf as *mut _ as *mut _;
// only attach cmsg if we successfully acquired the pidfd
if pidfd >= 0 {
+ msg.msg_controllen = mem::size_of_val(&cmsg.buf) as _;
+ msg.msg_control = &mut cmsg.buf as *mut _ as *mut _;
+
let hdr = CMSG_FIRSTHDR(&mut msg as *mut _ as *mut _);
(*hdr).cmsg_level = SOL_SOCKET;
(*hdr).cmsg_type = SCM_RIGHTS;
@@ -717,7 +720,7 @@ impl Command {
// so we get a consistent SEQPACKET order
match cvt_r(|| libc::sendmsg(sock.as_raw(), &msg, 0)) {
Ok(0) => {}
- _ => rtabort!("failed to communicate with parent process"),
+ other => rtabort!("failed to communicate with parent process. {:?}", other),
}
}
}
@@ -748,7 +751,7 @@ impl Command {
msg.msg_controllen = mem::size_of::<Cmsg>() as _;
msg.msg_control = &mut cmsg as *mut _ as *mut _;
- match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, 0)) {
+ match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, libc::MSG_CMSG_CLOEXEC)) {
Err(_) => return -1,
Ok(_) => {}
}
@@ -787,7 +790,7 @@ pub struct Process {
// On Linux, stores the pidfd created for this child.
// This is None if the user did not request pidfd creation,
// or if the pidfd could not be created for some reason
- // (e.g. the `clone3` syscall was not available).
+ // (e.g. the `pidfd_open` syscall was not available).
#[cfg(target_os = "linux")]
pidfd: Option<PidFd>,
}
@@ -816,10 +819,23 @@ impl Process {
// and used for another process, and we probably shouldn't be killing
// random processes, so return Ok because the process has exited already.
if self.status.is_some() {
- Ok(())
- } else {
- cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
+ return Ok(());
+ }
+ #[cfg(target_os = "linux")]
+ if let Some(pid_fd) = self.pidfd.as_ref() {
+ // pidfd_send_signal predates pidfd_open. so if we were able to get an fd then sending signals will work too
+ return cvt(unsafe {
+ libc::syscall(
+ libc::SYS_pidfd_send_signal,
+ pid_fd.as_raw_fd(),
+ libc::SIGKILL,
+ crate::ptr::null::<()>(),
+ 0,
+ )
+ })
+ .map(drop);
}
+ cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
}
pub fn wait(&mut self) -> io::Result<ExitStatus> {
@@ -827,6 +843,17 @@ impl Process {
if let Some(status) = self.status {
return Ok(status);
}
+ #[cfg(target_os = "linux")]
+ if let Some(pid_fd) = self.pidfd.as_ref() {
+ let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() };
+
+ cvt_r(|| unsafe {
+ libc::waitid(libc::P_PIDFD, pid_fd.as_raw_fd() as u32, &mut siginfo, libc::WEXITED)
+ })?;
+ let status = ExitStatus::from_waitid_siginfo(siginfo);
+ self.status = Some(status);
+ return Ok(status);
+ }
let mut status = 0 as c_int;
cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
self.status = Some(ExitStatus::new(status));
@@ -837,6 +864,25 @@ impl Process {
if let Some(status) = self.status {
return Ok(Some(status));
}
+ #[cfg(target_os = "linux")]
+ if let Some(pid_fd) = self.pidfd.as_ref() {
+ let mut siginfo: libc::siginfo_t = unsafe { crate::mem::zeroed() };
+
+ cvt(unsafe {
+ libc::waitid(
+ libc::P_PIDFD,
+ pid_fd.as_raw_fd() as u32,
+ &mut siginfo,
+ libc::WEXITED | libc::WNOHANG,
+ )
+ })?;
+ if unsafe { siginfo.si_pid() } == 0 {
+ return Ok(None);
+ }
+ let status = ExitStatus::from_waitid_siginfo(siginfo);
+ self.status = Some(status);
+ return Ok(Some(status));
+ }
let mut status = 0 as c_int;
let pid = cvt(unsafe { libc::waitpid(self.pid, &mut status, libc::WNOHANG) })?;
if pid == 0 {
@@ -866,6 +912,20 @@ impl ExitStatus {
ExitStatus(status)
}
+ #[cfg(target_os = "linux")]
+ pub fn from_waitid_siginfo(siginfo: libc::siginfo_t) -> ExitStatus {
+ let status = unsafe { siginfo.si_status() };
+
+ match siginfo.si_code {
+ libc::CLD_EXITED => ExitStatus((status & 0xff) << 8),
+ libc::CLD_KILLED => ExitStatus(status),
+ libc::CLD_DUMPED => ExitStatus(status | 0x80),
+ libc::CLD_CONTINUED => ExitStatus(0xffff),
+ libc::CLD_STOPPED | libc::CLD_TRAPPED => ExitStatus(((status & 0xff) << 8) | 0x7f),
+ _ => unreachable!("waitid() should only return the above codes"),
+ }
+ }
+
fn exited(&self) -> bool {
libc::WIFEXITED(self.0)
}
diff --git a/library/std/src/sys/unix/process/process_unix/tests.rs b/library/std/src/sys/unix/process/process_unix/tests.rs
index 6aa79e7f9..6e952ed7c 100644
--- a/library/std/src/sys/unix/process/process_unix/tests.rs
+++ b/library/std/src/sys/unix/process/process_unix/tests.rs
@@ -64,7 +64,8 @@ fn test_command_fork_no_unwind() {
#[test]
#[cfg(target_os = "linux")]
fn test_command_pidfd() {
- use crate::os::fd::RawFd;
+ use crate::assert_matches::assert_matches;
+ use crate::os::fd::{AsRawFd, RawFd};
use crate::os::linux::process::{ChildExt, CommandExt};
use crate::process::Command;
@@ -78,10 +79,22 @@ fn test_command_pidfd() {
};
// always exercise creation attempts
- let child = Command::new("echo").create_pidfd(true).spawn().unwrap();
+ let mut child = Command::new("false").create_pidfd(true).spawn().unwrap();
// but only check if we know that the kernel supports pidfds
if pidfd_open_available {
- assert!(child.pidfd().is_ok())
+ assert!(child.pidfd().is_ok());
}
+ if let Ok(pidfd) = child.pidfd() {
+ let flags = super::cvt(unsafe { libc::fcntl(pidfd.as_raw_fd(), libc::F_GETFD) }).unwrap();
+ assert!(flags & libc::FD_CLOEXEC != 0);
+ }
+ let status = child.wait().expect("error waiting on pidfd");
+ assert_eq!(status.code(), Some(1));
+
+ let mut child = Command::new("sleep").arg("1000").create_pidfd(true).spawn().unwrap();
+ assert_matches!(child.try_wait(), Ok(None));
+ child.kill().expect("failed to kill child");
+ let status = child.wait().expect("error waiting on pidfd");
+ assert_eq!(status.signal(), Some(libc::SIGKILL));
}
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 29db9468e..76b96bb37 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -163,10 +163,9 @@ impl Thread {
#[cfg(target_os = "netbsd")]
pub fn set_name(name: &CStr) {
unsafe {
- let cname = CStr::from_bytes_with_nul_unchecked(b"%s\0".as_slice());
let res = libc::pthread_setname_np(
libc::pthread_self(),
- cname.as_ptr(),
+ c"%s".as_ptr(),
name.as_ptr() as *mut libc::c_void,
);
debug_assert_eq!(res, 0);
diff --git a/library/std/src/sys/unix/thread_local_dtor.rs b/library/std/src/sys/unix/thread_local_dtor.rs
index 06399e8a2..ac85531c3 100644
--- a/library/std/src/sys/unix/thread_local_dtor.rs
+++ b/library/std/src/sys/unix/thread_local_dtor.rs
@@ -12,7 +12,13 @@
// compiling from a newer linux to an older linux, so we also have a
// fallback implementation to use as well.
#[allow(unexpected_cfgs)]
-#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox", target_os = "hurd"))]
+#[cfg(any(
+ target_os = "linux",
+ target_os = "android",
+ target_os = "fuchsia",
+ target_os = "redox",
+ target_os = "hurd"
+))]
// FIXME: The Rust compiler currently omits weakly function definitions (i.e.,
// __cxa_thread_atexit_impl) and its metadata from LLVM IR.
#[no_sanitize(cfi, kcfi)]
@@ -23,6 +29,8 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
/// This is necessary because the __cxa_thread_atexit_impl implementation
/// std links to by default may be a C or C++ implementation that was not
/// compiled using the Clang integer normalization option.
+ #[cfg(sanitizer_cfi_normalize_integers)]
+ use core::ffi::c_int;
#[cfg(not(sanitizer_cfi_normalize_integers))]
#[cfi_encoding = "i"]
#[repr(transparent)]
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index f2e86a4fb..f62eb828e 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -23,11 +23,11 @@ struct Nanoseconds(u32);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SystemTime {
- pub(in crate::sys::unix) t: Timespec,
+ pub(crate) t: Timespec,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub(in crate::sys::unix) struct Timespec {
+pub(crate) struct Timespec {
tv_sec: i64,
tv_nsec: Nanoseconds,
}
@@ -239,11 +239,11 @@ impl From<libc::timespec> for Timespec {
not(target_arch = "riscv32")
))]
#[repr(C)]
-pub(in crate::sys::unix) struct __timespec64 {
- pub(in crate::sys::unix) tv_sec: i64,
+pub(crate) struct __timespec64 {
+ pub(crate) tv_sec: i64,
#[cfg(target_endian = "big")]
_padding: i32,
- pub(in crate::sys::unix) tv_nsec: i32,
+ pub(crate) tv_nsec: i32,
#[cfg(target_endian = "little")]
_padding: i32,
}
@@ -255,7 +255,7 @@ pub(in crate::sys::unix) struct __timespec64 {
not(target_arch = "riscv32")
))]
impl __timespec64 {
- pub(in crate::sys::unix) fn new(tv_sec: i64, tv_nsec: i32) -> Self {
+ pub(crate) fn new(tv_sec: i64, tv_nsec: i32) -> Self {
Self { tv_sec, tv_nsec, _padding: 0 }
}
}
diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index 437aae3ae..e82386654 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -477,12 +477,13 @@ impl File {
}
pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
- let to_timestamp = |time: Option<SystemTime>| {
- match time {
- Some(time) if let Some(ts) = time.to_wasi_timestamp() => Ok(ts),
- Some(_) => Err(io::const_io_error!(io::ErrorKind::InvalidInput, "timestamp is too large to set as a file time")),
- None => Ok(0),
- }
+ let to_timestamp = |time: Option<SystemTime>| match time {
+ Some(time) if let Some(ts) = time.to_wasi_timestamp() => Ok(ts),
+ Some(_) => Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "timestamp is too large to set as a file time"
+ )),
+ None => Ok(0),
};
self.fd.filestat_set_times(
to_timestamp(times.accessed)?,
diff --git a/library/std/src/sys/windows/api.rs b/library/std/src/sys/windows/api.rs
index e9f0bbfbe..a7ea59e85 100644
--- a/library/std/src/sys/windows/api.rs
+++ b/library/std/src/sys/windows/api.rs
@@ -48,7 +48,7 @@ use super::c;
/// converted to a `u32`. Clippy would warn about this but, alas, it's not run
/// on the standard library.
const fn win32_size_of<T: Sized>() -> u32 {
- // Const assert that the size is less than u32::MAX.
+ // Const assert that the size does not exceed u32::MAX.
// Uses a trait to workaround restriction on using generic types in inner items.
trait Win32SizeOf: Sized {
const WIN32_SIZE_OF: u32 = {
@@ -132,7 +132,7 @@ pub fn set_file_information_by_handle<T: SetFileInformation>(
size: u32,
) -> Result<(), WinError> {
let result = c::SetFileInformationByHandle(handle, class, info, size);
- (result != 0).then_some(()).ok_or_else(|| get_last_error())
+ (result != 0).then_some(()).ok_or_else(get_last_error)
}
// SAFETY: The `SetFileInformation` trait ensures that this is safe.
unsafe { set_info(handle, T::CLASS, info.as_ptr(), info.size()) }
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index a349e24b0..d55d9bace 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -3,6 +3,7 @@
#![allow(nonstandard_style)]
#![cfg_attr(test, allow(dead_code))]
#![unstable(issue = "none", feature = "windows_c")]
+#![allow(clippy::style)]
use crate::ffi::CStr;
use crate::mem;
@@ -46,6 +47,8 @@ pub use FD_SET as fd_set;
pub use LINGER as linger;
pub use TIMEVAL as timeval;
+pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::invalid_mut(-1i32 as _);
+
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure?view=msvc-170
pub const EXIT_SUCCESS: u32 = 0;
pub const EXIT_FAILURE: u32 = 1;
@@ -81,7 +84,7 @@ pub fn nt_success(status: NTSTATUS) -> bool {
impl UNICODE_STRING {
pub fn from_ref(slice: &[u16]) -> Self {
- let len = slice.len() * mem::size_of::<u16>();
+ let len = mem::size_of_val(slice);
Self { Length: len as _, MaximumLength: len as _, Buffer: slice.as_ptr() as _ }
}
}
@@ -321,7 +324,7 @@ pub unsafe fn NtWriteFile(
// Functions that aren't available on every version of Windows that we support,
// but we still use them and just provide some form of a fallback implementation.
compat_fn_with_fallback! {
- pub static KERNEL32: &CStr = ansi_str!("kernel32");
+ pub static KERNEL32: &CStr = c"kernel32";
// >= Win10 1607
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreaddescription
@@ -354,7 +357,7 @@ compat_fn_optional! {
}
compat_fn_with_fallback! {
- pub static NTDLL: &CStr = ansi_str!("ntdll");
+ pub static NTDLL: &CStr = c"ntdll";
pub fn NtCreateKeyedEvent(
KeyedEventHandle: LPHANDLE,
diff --git a/library/std/src/sys/windows/c/windows_sys.lst b/library/std/src/sys/windows/c/windows_sys.lst
index 38bf15b7c..f91e1054a 100644
--- a/library/std/src/sys/windows/c/windows_sys.lst
+++ b/library/std/src/sys/windows/c/windows_sys.lst
@@ -2,6 +2,7 @@
--config flatten std
--filter
// tidy-alphabetical-start
+!Windows.Win32.Foundation.INVALID_HANDLE_VALUE
Windows.Wdk.Storage.FileSystem.FILE_COMPLETE_IF_OPLOCKED
Windows.Wdk.Storage.FileSystem.FILE_CONTAINS_EXTENDED_CREATE_INFORMATION
Windows.Wdk.Storage.FileSystem.FILE_CREATE
@@ -1923,7 +1924,6 @@ Windows.Win32.Foundation.HANDLE_FLAG_INHERIT
Windows.Win32.Foundation.HANDLE_FLAG_PROTECT_FROM_CLOSE
Windows.Win32.Foundation.HANDLE_FLAGS
Windows.Win32.Foundation.HMODULE
-Windows.Win32.Foundation.INVALID_HANDLE_VALUE
Windows.Win32.Foundation.MAX_PATH
Windows.Win32.Foundation.NO_ERROR
Windows.Win32.Foundation.NTSTATUS
@@ -2483,7 +2483,6 @@ Windows.Win32.System.SystemInformation.GetSystemTimeAsFileTime
Windows.Win32.System.SystemInformation.GetWindowsDirectoryW
Windows.Win32.System.SystemInformation.PROCESSOR_ARCHITECTURE
Windows.Win32.System.SystemInformation.SYSTEM_INFO
-Windows.Win32.System.SystemServices.ALL_PROCESSOR_GROUPS
Windows.Win32.System.SystemServices.DLL_PROCESS_DETACH
Windows.Win32.System.SystemServices.DLL_THREAD_DETACH
Windows.Win32.System.SystemServices.EXCEPTION_MAXIMUM_PARAMETERS
@@ -2492,6 +2491,7 @@ Windows.Win32.System.SystemServices.IO_REPARSE_TAG_SYMLINK
Windows.Win32.System.Threading.ABOVE_NORMAL_PRIORITY_CLASS
Windows.Win32.System.Threading.AcquireSRWLockExclusive
Windows.Win32.System.Threading.AcquireSRWLockShared
+Windows.Win32.System.Threading.ALL_PROCESSOR_GROUPS
Windows.Win32.System.Threading.BELOW_NORMAL_PRIORITY_CLASS
Windows.Win32.System.Threading.CREATE_BREAKAWAY_FROM_JOB
Windows.Win32.System.Threading.CREATE_DEFAULT_ERROR_MODE
diff --git a/library/std/src/sys/windows/c/windows_sys.rs b/library/std/src/sys/windows/c/windows_sys.rs
index e0509e6a5..b38b70c89 100644
--- a/library/std/src/sys/windows/c/windows_sys.rs
+++ b/library/std/src/sys/windows/c/windows_sys.rs
@@ -4,7 +4,7 @@
// regenerate the bindings.
//
// ignore-tidy-filelength
-// Bindings generated by `windows-bindgen` 0.51.1
+// Bindings generated by `windows-bindgen` 0.52.0
#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
#[link(name = "advapi32")]
@@ -63,7 +63,7 @@ extern "system" {
lpnewfilename: PCWSTR,
lpprogressroutine: LPPROGRESS_ROUTINE,
lpdata: *const ::core::ffi::c_void,
- pbcancel: *mut i32,
+ pbcancel: *mut BOOL,
dwcopyflags: u32,
) -> BOOL;
}
@@ -619,7 +619,7 @@ extern "system" {
lpmultibytestr: PSTR,
cbmultibyte: i32,
lpdefaultchar: PCSTR,
- lpuseddefaultchar: *mut i32,
+ lpuseddefaultchar: *mut BOOL,
) -> i32;
}
#[link(name = "kernel32")]
@@ -869,7 +869,7 @@ pub const AF_INET: ADDRESS_FAMILY = 2u16;
pub const AF_INET6: ADDRESS_FAMILY = 23u16;
pub const AF_UNIX: u16 = 1u16;
pub const AF_UNSPEC: ADDRESS_FAMILY = 0u16;
-pub const ALL_PROCESSOR_GROUPS: u32 = 65535u32;
+pub const ALL_PROCESSOR_GROUPS: u16 = 65535u16;
#[repr(C)]
pub union ARM64_NT_NEON128 {
pub Anonymous: ARM64_NT_NEON128_0,
@@ -3498,7 +3498,6 @@ impl ::core::clone::Clone for INIT_ONCE {
}
pub const INIT_ONCE_INIT_FAILED: u32 = 4u32;
pub const INVALID_FILE_ATTRIBUTES: u32 = 4294967295u32;
-pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::invalid_mut(-1i32 as _);
pub const INVALID_SOCKET: SOCKET = -1i32 as _;
#[repr(C)]
pub struct IN_ADDR {
diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs
index e28dd4935..f60b3a2c7 100644
--- a/library/std/src/sys/windows/compat.rs
+++ b/library/std/src/sys/windows/compat.rs
@@ -225,9 +225,9 @@ macro_rules! compat_fn_optional {
/// 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");
+ const MODULE_NAME: &CStr = c"api-ms-win-core-synch-l1-2-0";
+ const WAIT_ON_ADDRESS: &CStr = c"WaitOnAddress";
+ const WAKE_BY_ADDRESS_SINGLE: &CStr = c"WakeByAddressSingle";
// Try loading the library and all the required functions.
// If any step fails, then they all fail.
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index d7e36b9a3..424845436 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -1,7 +1,7 @@
use crate::os::windows::prelude::*;
use crate::borrow::Cow;
-use crate::ffi::OsString;
+use crate::ffi::{c_void, OsString};
use crate::fmt;
use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom};
use crate::mem::{self, MaybeUninit};
@@ -16,8 +16,6 @@ use crate::sys::{c, cvt, Align8};
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::thread;
-use core::ffi::c_void;
-
use super::path::maybe_verbatim;
use super::{api, to_u16s, IoResult};
@@ -156,7 +154,7 @@ impl DirEntry {
}
pub fn path(&self) -> PathBuf {
- self.root.join(&self.file_name())
+ self.root.join(self.file_name())
}
pub fn file_name(&self) -> OsString {
@@ -273,7 +271,9 @@ impl OpenOptions {
(false, false, false) => c::OPEN_EXISTING,
(true, false, false) => c::OPEN_ALWAYS,
(false, true, false) => c::TRUNCATE_EXISTING,
- (true, true, false) => c::CREATE_ALWAYS,
+ // `CREATE_ALWAYS` has weird semantics so we emulate it using
+ // `OPEN_ALWAYS` and a manual truncation step. See #115745.
+ (true, true, false) => c::OPEN_ALWAYS,
(_, _, true) => c::CREATE_NEW,
})
}
@@ -289,19 +289,42 @@ impl OpenOptions {
impl File {
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
let path = maybe_verbatim(path)?;
+ let creation = opts.get_creation_mode()?;
let handle = unsafe {
c::CreateFileW(
path.as_ptr(),
opts.get_access_mode()?,
opts.share_mode,
opts.security_attributes,
- opts.get_creation_mode()?,
+ creation,
opts.get_flags_and_attributes(),
ptr::null_mut(),
)
};
let handle = unsafe { HandleOrInvalid::from_raw_handle(handle) };
- if let Ok(handle) = handle.try_into() {
+ if let Ok(handle) = OwnedHandle::try_from(handle) {
+ // Manual truncation. See #115745.
+ if opts.truncate
+ && creation == c::OPEN_ALWAYS
+ && unsafe { c::GetLastError() } == c::ERROR_ALREADY_EXISTS
+ {
+ unsafe {
+ // This originally used `FileAllocationInfo` instead of
+ // `FileEndOfFileInfo` but that wasn't supported by WINE.
+ // It's arguable which fits the semantics of `OpenOptions`
+ // better so let's just use the more widely supported method.
+ let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 };
+ let result = c::SetFileInformationByHandle(
+ handle.as_raw_handle(),
+ c::FileEndOfFileInfo,
+ ptr::addr_of!(eof).cast::<c_void>(),
+ mem::size_of::<c::FILE_END_OF_FILE_INFO>() as u32,
+ );
+ if result == 0 {
+ return Err(io::Error::last_os_error());
+ }
+ }
+ }
Ok(File { handle: Handle::from_inner(handle) })
} else {
Err(Error::last_os_error())
@@ -548,7 +571,7 @@ impl File {
let user = super::args::from_wide_to_user_path(
subst.iter().copied().chain([0]).collect(),
)?;
- Ok(PathBuf::from(OsString::from_wide(&user.strip_suffix(&[0]).unwrap_or(&user))))
+ Ok(PathBuf::from(OsString::from_wide(user.strip_suffix(&[0]).unwrap_or(&user))))
} else {
Ok(PathBuf::from(OsString::from_wide(subst)))
}
@@ -786,7 +809,7 @@ fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result<
// tricked into following a symlink. However, it may not be available in
// earlier versions of Windows.
static ATTRIBUTES: AtomicU32 = AtomicU32::new(c::OBJ_DONT_REPARSE);
- let mut object = c::OBJECT_ATTRIBUTES {
+ let object = c::OBJECT_ATTRIBUTES {
ObjectName: &mut name_str,
RootDirectory: parent.as_raw_handle(),
Attributes: ATTRIBUTES.load(Ordering::Relaxed),
@@ -795,7 +818,7 @@ fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result<
let status = c::NtCreateFile(
&mut handle,
access,
- &mut object,
+ &object,
&mut io_status,
crate::ptr::null_mut(),
0,
@@ -874,7 +897,7 @@ impl fmt::Debug for File {
// FIXME(#24570): add more info here (e.g., mode)
let mut b = f.debug_struct("File");
b.field("handle", &self.handle.as_raw_handle());
- if let Ok(path) = get_path(&self) {
+ if let Ok(path) = get_path(self) {
b.field("path", &path);
}
b.finish()
@@ -1193,7 +1216,7 @@ pub fn readlink(path: &Path) -> io::Result<PathBuf> {
let mut opts = OpenOptions::new();
opts.access_mode(0);
opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS);
- let file = File::open(&path, &opts)?;
+ let file = File::open(path, &opts)?;
file.readlink()
}
@@ -1407,7 +1430,7 @@ pub fn symlink_junction<P: AsRef<Path>, Q: AsRef<Path>>(
#[allow(dead_code)]
fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
let d = DirBuilder::new();
- d.mkdir(&junction)?;
+ d.mkdir(junction)?;
let mut opts = OpenOptions::new();
opts.write(true);
diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs
index 56d0d6c08..c4495f81a 100644
--- a/library/std/src/sys/windows/handle.rs
+++ b/library/std/src/sys/windows/handle.rs
@@ -81,7 +81,7 @@ impl Handle {
let res = unsafe { self.synchronous_read(buf.as_mut_ptr().cast(), buf.len(), None) };
match res {
- Ok(read) => Ok(read as usize),
+ Ok(read) => Ok(read),
// The special treatment of BrokenPipe is to deal with Windows
// pipe semantics, which yields this error when *reading* from
@@ -107,7 +107,7 @@ impl Handle {
unsafe { self.synchronous_read(buf.as_mut_ptr().cast(), buf.len(), Some(offset)) };
match res {
- Ok(read) => Ok(read as usize),
+ Ok(read) => Ok(read),
Err(ref e) if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) => Ok(0),
Err(e) => Err(e),
}
@@ -121,7 +121,7 @@ impl Handle {
Ok(read) => {
// Safety: `read` bytes were written to the initialized portion of the buffer
unsafe {
- cursor.advance(read as usize);
+ cursor.advance(read);
}
Ok(())
}
@@ -189,7 +189,7 @@ impl Handle {
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
- self.synchronous_write(&buf, None)
+ self.synchronous_write(buf, None)
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
@@ -202,7 +202,7 @@ impl Handle {
}
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
- self.synchronous_write(&buf, Some(offset))
+ self.synchronous_write(buf, Some(offset))
}
pub fn try_clone(&self) -> io::Result<Self> {
diff --git a/library/std/src/sys/windows/io.rs b/library/std/src/sys/windows/io.rs
index 9b540ee07..649826d25 100644
--- a/library/std/src/sys/windows/io.rs
+++ b/library/std/src/sys/windows/io.rs
@@ -36,7 +36,7 @@ impl<'a> IoSlice<'a> {
#[inline]
pub fn as_slice(&self) -> &[u8] {
- unsafe { slice::from_raw_parts(self.vec.buf as *mut u8, self.vec.len as usize) }
+ unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) }
}
}
@@ -70,12 +70,12 @@ impl<'a> IoSliceMut<'a> {
#[inline]
pub fn as_slice(&self) -> &[u8] {
- unsafe { slice::from_raw_parts(self.vec.buf as *mut u8, self.vec.len as usize) }
+ unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) }
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
- unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.len as usize) }
+ unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) }
}
}
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index c4e56e13b..8b722f01a 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -1,6 +1,6 @@
#![allow(missing_docs, nonstandard_style)]
-use crate::ffi::{CStr, OsStr, OsString};
+use crate::ffi::{OsStr, OsString};
use crate::io::ErrorKind;
use crate::mem::MaybeUninit;
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
@@ -63,7 +63,7 @@ pub unsafe fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {
// Normally, `thread::spawn` will call `Thread::set_name` but since this thread already
// exists, we have to call it ourselves.
- thread::Thread::set_name(&CStr::from_bytes_with_nul_unchecked(b"main\0"));
+ thread::Thread::set_name(&c"main");
}
// SAFETY: must be called only once during runtime cleanup.
@@ -150,7 +150,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
let ptr = haystack.as_ptr();
- let mut start = &haystack[..];
+ let mut start = haystack;
// For performance reasons unfold the loop eight times.
while start.len() >= 8 {
diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs
index c29b86366..6cd758ec5 100644
--- a/library/std/src/sys/windows/net.rs
+++ b/library/std/src/sys/windows/net.rs
@@ -162,7 +162,7 @@ impl Socket {
let mut timeout = c::timeval {
tv_sec: cmp::min(timeout.as_secs(), c_long::MAX as u64) as c_long,
- tv_usec: (timeout.subsec_nanos() / 1000) as c_long,
+ tv_usec: timeout.subsec_micros() as c_long,
};
if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs
index 8cc905101..829dd5eb9 100644
--- a/library/std/src/sys/windows/os.rs
+++ b/library/std/src/sys/windows/os.rs
@@ -297,7 +297,7 @@ pub fn getenv(k: &OsStr) -> Option<OsString> {
let k = to_u16s(k).ok()?;
super::fill_utf16_buf(
|buf, sz| unsafe { c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) },
- |buf| OsStringExt::from_wide(buf),
+ OsStringExt::from_wide,
)
.ok()
}
@@ -356,7 +356,7 @@ pub fn home_dir() -> Option<PathBuf> {
crate::env::var_os("HOME")
.or_else(|| crate::env::var_os("USERPROFILE"))
.map(PathBuf::from)
- .or_else(|| home_dir_crt())
+ .or_else(home_dir_crt)
}
pub fn exit(code: i32) -> ! {
@@ -364,5 +364,5 @@ pub fn exit(code: i32) -> ! {
}
pub fn getpid() -> u32 {
- unsafe { c::GetCurrentProcessId() as u32 }
+ unsafe { c::GetCurrentProcessId() }
}
diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs
index 8c0e07b35..d9684f217 100644
--- a/library/std/src/sys/windows/path.rs
+++ b/library/std/src/sys/windows/path.rs
@@ -78,7 +78,7 @@ impl<'a> PrefixParserSlice<'a, '_> {
fn strip_prefix(&self, prefix: &str) -> Option<Self> {
self.prefix[self.index..]
.starts_with(prefix.as_bytes())
- .then(|| Self { index: self.index + prefix.len(), ..*self })
+ .then_some(Self { index: self.index + prefix.len(), ..*self })
}
fn prefix_bytes(&self) -> &'a [u8] {
@@ -104,7 +104,9 @@ pub fn parse_prefix(path: &OsStr) -> Option<Prefix<'_>> {
// The meaning of verbatim paths can change when they use a different
// separator.
- if let Some(parser) = parser.strip_prefix(r"?\") && !parser.prefix_bytes().iter().any(|&x| x == b'/') {
+ if let Some(parser) = parser.strip_prefix(r"?\")
+ && !parser.prefix_bytes().iter().any(|&x| x == b'/')
+ {
// \\?\
if let Some(parser) = parser.strip_prefix(r"UNC\") {
// \\?\UNC\server\share
@@ -145,12 +147,10 @@ pub fn parse_prefix(path: &OsStr) -> Option<Prefix<'_>> {
None
}
}
- } else if let Some(drive) = parse_drive(path) {
- // C:
- Some(Disk(drive))
} else {
- // no prefix
- None
+ // If it has a drive like `C:` then it's a disk.
+ // Otherwise there is no prefix.
+ parse_drive(path).map(Disk)
}
}
@@ -250,7 +250,7 @@ pub(crate) fn get_long_path(mut path: Vec<u16>, prefer_verbatim: bool) -> io::Re
// \\?\UNC\
const UNC_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP, U, N, C, SEP];
- if path.starts_with(VERBATIM_PREFIX) || path.starts_with(NT_PREFIX) || path == &[0] {
+ if path.starts_with(VERBATIM_PREFIX) || path.starts_with(NT_PREFIX) || path == [0] {
// Early return for paths that are already verbatim or empty.
return Ok(path);
} else if path.len() < LEGACY_MAX_PATH {
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index f4078d359..9ec775959 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -245,7 +245,7 @@ impl Command {
}
pub fn get_current_dir(&self) -> Option<&Path> {
- self.cwd.as_ref().map(|cwd| Path::new(cwd))
+ self.cwd.as_ref().map(Path::new)
}
pub unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
@@ -463,7 +463,7 @@ fn resolve_exe<'a>(
// Search the directories given by `search_paths`.
let result = search_paths(parent_paths, child_paths, |mut path| {
- path.push(&exe_path);
+ path.push(exe_path);
if !has_extension {
path.set_extension(EXE_EXTENSION);
}
@@ -597,7 +597,7 @@ impl Stdio {
opts.read(stdio_id == c::STD_INPUT_HANDLE);
opts.write(stdio_id != c::STD_INPUT_HANDLE);
opts.security_attributes(&mut sa);
- File::open(Path::new("NUL"), &opts).map(|file| file.into_inner())
+ File::open(Path::new(r"\\.\NUL"), &opts).map(|file| file.into_inner())
}
}
}
@@ -657,7 +657,7 @@ impl Process {
}
pub fn id(&self) -> u32 {
- unsafe { c::GetProcessId(self.handle.as_raw_handle()) as u32 }
+ unsafe { c::GetProcessId(self.handle.as_raw_handle()) }
}
pub fn main_thread_handle(&self) -> BorrowedHandle<'_> {
@@ -917,9 +917,8 @@ fn make_proc_thread_attribute_list(
)
};
- let mut proc_thread_attribute_list = ProcThreadAttributeList(
- vec![MaybeUninit::uninit(); required_size as usize].into_boxed_slice(),
- );
+ let mut proc_thread_attribute_list =
+ ProcThreadAttributeList(vec![MaybeUninit::uninit(); required_size].into_boxed_slice());
// Once we've allocated the necessary memory, it's safe to invoke
// `InitializeProcThreadAttributeList` to properly initialize the list.
diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs
index a9ff909aa..819a48266 100644
--- a/library/std/src/sys/windows/stdio.rs
+++ b/library/std/src/sys/windows/stdio.rs
@@ -195,7 +195,7 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usiz
MaybeUninit::slice_assume_init_ref(&utf16[..result as usize])
};
- let mut written = write_u16s(handle, &utf16)?;
+ let mut written = write_u16s(handle, utf16)?;
// Figure out how many bytes of as UTF-8 were written away as UTF-16.
if written == utf16.len() {
@@ -207,7 +207,7 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usiz
// write the missing surrogate out now.
// Buffering it would mean we have to lie about the number of bytes written.
let first_code_unit_remaining = utf16[written];
- if first_code_unit_remaining >= 0xDCEE && first_code_unit_remaining <= 0xDFFF {
+ if matches!(first_code_unit_remaining, 0xDCEE..=0xDFFF) {
// low surrogate
// We just hope this works, and give up otherwise
let _ = write_u16s(handle, &utf16[written..written + 1]);
@@ -266,7 +266,7 @@ impl io::Read for Stdin {
let mut bytes_copied = self.incomplete_utf8.read(buf);
if bytes_copied == buf.len() {
- return Ok(bytes_copied);
+ Ok(bytes_copied)
} else if buf.len() - bytes_copied < 4 {
// Not enough space to get a UTF-8 byte. We will use the incomplete UTF8.
let mut utf16_buf = [MaybeUninit::new(0); 1];
@@ -332,7 +332,7 @@ fn read_u16s_fixup_surrogates(
// and it is not 0, so we know that `buf[amount - 1]` have been
// initialized.
let last_char = unsafe { buf[amount - 1].assume_init() };
- if last_char >= 0xD800 && last_char <= 0xDBFF {
+ if matches!(last_char, 0xD800..=0xDBFF) {
// high surrogate
*surrogate = last_char;
amount -= 1;
diff --git a/library/std/src/sys/windows/time.rs b/library/std/src/sys/windows/time.rs
index bece48e79..09e78a293 100644
--- a/library/std/src/sys/windows/time.rs
+++ b/library/std/src/sys/windows/time.rs
@@ -1,7 +1,7 @@
use crate::cmp::Ordering;
use crate::fmt;
use crate::mem;
-use crate::ptr::{null, null_mut};
+use crate::ptr::null;
use crate::sys::c;
use crate::sys_common::IntoInner;
use crate::time::Duration;
@@ -240,7 +240,7 @@ impl WaitableTimer {
c::TIMER_ALL_ACCESS,
)
};
- if handle != null_mut() { Ok(Self { handle }) } else { Err(()) }
+ if !handle.is_null() { Ok(Self { handle }) } else { Err(()) }
}
pub fn set(&self, duration: Duration) -> Result<(), ()> {
// Convert the Duration to a format similar to FILETIME.
diff --git a/library/std/src/sys/xous/mod.rs b/library/std/src/sys/xous/mod.rs
index 6d5c218d1..c2550dcfd 100644
--- a/library/std/src/sys/xous/mod.rs
+++ b/library/std/src/sys/xous/mod.rs
@@ -28,7 +28,6 @@ pub mod process;
pub mod stdio;
pub mod thread;
pub mod thread_local_key;
-#[path = "../unsupported/thread_parking.rs"]
pub mod thread_parking;
pub mod time;
diff --git a/library/std/src/sys/xous/os.rs b/library/std/src/sys/xous/os.rs
index 3d19fa4b3..8d2eaee8a 100644
--- a/library/std/src/sys/xous/os.rs
+++ b/library/std/src/sys/xous/os.rs
@@ -8,6 +8,28 @@ use crate::os::xous::ffi::Error as XousError;
use crate::path::{self, PathBuf};
#[cfg(not(test))]
+#[cfg(feature = "panic_unwind")]
+mod eh_unwinding {
+ pub(crate) struct EhFrameFinder(usize /* eh_frame */);
+ pub(crate) static mut EH_FRAME_SETTINGS: EhFrameFinder = EhFrameFinder(0);
+ impl EhFrameFinder {
+ pub(crate) unsafe fn init(&mut self, eh_frame: usize) {
+ unsafe {
+ EH_FRAME_SETTINGS.0 = eh_frame;
+ }
+ }
+ }
+ unsafe impl unwind::EhFrameFinder for EhFrameFinder {
+ fn find(&self, _pc: usize) -> Option<unwind::FrameInfo> {
+ Some(unwind::FrameInfo {
+ text_base: None,
+ kind: unwind::FrameInfoKind::EhFrame(self.0),
+ })
+ }
+ }
+}
+
+#[cfg(not(test))]
mod c_compat {
use crate::os::xous::ffi::exit;
extern "C" {
@@ -20,7 +42,12 @@ mod c_compat {
}
#[no_mangle]
- pub extern "C" fn _start() {
+ pub extern "C" fn _start(eh_frame: usize) {
+ #[cfg(feature = "panic_unwind")]
+ unsafe {
+ super::eh_unwinding::EH_FRAME_SETTINGS.init(eh_frame);
+ unwind::set_custom_eh_frame_finder(&super::eh_unwinding::EH_FRAME_SETTINGS).ok();
+ }
exit(unsafe { main() });
}
diff --git a/library/std/src/sys/xous/thread_parking.rs b/library/std/src/sys/xous/thread_parking.rs
new file mode 100644
index 000000000..aa39c6d27
--- /dev/null
+++ b/library/std/src/sys/xous/thread_parking.rs
@@ -0,0 +1,94 @@
+use crate::os::xous::ffi::{blocking_scalar, scalar};
+use crate::os::xous::services::{ticktimer_server, TicktimerScalar};
+use crate::pin::Pin;
+use crate::ptr;
+use crate::sync::atomic::{
+ AtomicI8,
+ Ordering::{Acquire, Release},
+};
+use crate::time::Duration;
+
+const NOTIFIED: i8 = 1;
+const EMPTY: i8 = 0;
+const PARKED: i8 = -1;
+
+pub struct Parker {
+ state: AtomicI8,
+}
+
+impl Parker {
+ pub unsafe fn new_in_place(parker: *mut Parker) {
+ unsafe { parker.write(Parker { state: AtomicI8::new(EMPTY) }) }
+ }
+
+ fn index(&self) -> usize {
+ ptr::from_ref(self).addr()
+ }
+
+ pub unsafe fn park(self: Pin<&Self>) {
+ // Change NOTIFIED to EMPTY and EMPTY to PARKED.
+ let state = self.state.fetch_sub(1, Acquire);
+ if state == NOTIFIED {
+ return;
+ }
+
+ // The state was set to PARKED. Wait until the `unpark` wakes us up.
+ blocking_scalar(
+ ticktimer_server(),
+ TicktimerScalar::WaitForCondition(self.index(), 0).into(),
+ )
+ .expect("failed to send WaitForCondition command");
+
+ self.state.swap(EMPTY, Acquire);
+ }
+
+ pub unsafe fn park_timeout(self: Pin<&Self>, timeout: Duration) {
+ // Change NOTIFIED to EMPTY and EMPTY to PARKED.
+ let state = self.state.fetch_sub(1, Acquire);
+ if state == NOTIFIED {
+ return;
+ }
+
+ // A value of zero indicates an indefinite wait. Clamp the number of
+ // milliseconds to the allowed range.
+ let millis = usize::max(timeout.as_millis().try_into().unwrap_or(usize::MAX), 1);
+
+ let was_timeout = blocking_scalar(
+ ticktimer_server(),
+ TicktimerScalar::WaitForCondition(self.index(), millis).into(),
+ )
+ .expect("failed to send WaitForCondition command")[0]
+ != 0;
+
+ let state = self.state.swap(EMPTY, Acquire);
+ if was_timeout && state == NOTIFIED {
+ // The state was set to NOTIFIED after we returned from the wait
+ // but before we reset the state. Therefore, a wakeup is on its
+ // way, which we need to consume here.
+ // NOTICE: this is a priority hole.
+ blocking_scalar(
+ ticktimer_server(),
+ TicktimerScalar::WaitForCondition(self.index(), 0).into(),
+ )
+ .expect("failed to send WaitForCondition command");
+ }
+ }
+
+ pub fn unpark(self: Pin<&Self>) {
+ let state = self.state.swap(NOTIFIED, Release);
+ if state == PARKED {
+ // The thread is parked, wake it up.
+ blocking_scalar(
+ ticktimer_server(),
+ TicktimerScalar::NotifyCondition(self.index(), 1).into(),
+ )
+ .expect("failed to send NotifyCondition command");
+ }
+ }
+}
+
+impl Drop for Parker {
+ fn drop(&mut self) {
+ scalar(ticktimer_server(), TicktimerScalar::FreeCondition(self.index()).into()).ok();
+ }
+}
diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs
index 84e2c5d8d..adfe721cf 100644
--- a/library/std/src/sys_common/backtrace.rs
+++ b/library/std/src/sys_common/backtrace.rs
@@ -64,6 +64,7 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::
let mut first_omit = true;
// Start immediately if we're not using a short backtrace.
let mut start = print_fmt != PrintFmt::Short;
+ set_image_base();
backtrace_rs::trace_unsynchronized(|frame| {
if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
return false;
@@ -213,3 +214,14 @@ pub fn output_filename(
}
fmt::Display::fmt(&file.display(), fmt)
}
+
+#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
+pub fn set_image_base() {
+ let image_base = crate::os::fortanix_sgx::mem::image_base();
+ backtrace_rs::set_image_base(crate::ptr::invalid_mut(image_base as _));
+}
+
+#[cfg(not(all(target_vendor = "fortanix", target_env = "sgx")))]
+pub fn set_image_base() {
+ // nothing to do for platforms other than SGX
+}
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index e18638f2a..851832a37 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -43,15 +43,15 @@ cfg_if::cfg_if! {
}
cfg_if::cfg_if! {
- if #[cfg(any(target_os = "l4re",
- target_os = "uefi",
- feature = "restricted-std",
- all(target_family = "wasm", not(target_os = "emscripten")),
- target_os = "xous",
- all(target_vendor = "fortanix", target_env = "sgx")))] {
- pub use crate::sys::net;
- } else {
+ if #[cfg(any(
+ all(unix, not(target_os = "l4re")),
+ windows,
+ target_os = "hermit",
+ target_os = "solid_asp3"
+ ))] {
pub mod net;
+ } else {
+ pub use crate::sys::net;
}
}
diff --git a/library/std/src/sys_common/once/futex.rs b/library/std/src/sys_common/once/futex.rs
index 42db5fad4..609085dcd 100644
--- a/library/std/src/sys_common/once/futex.rs
+++ b/library/std/src/sys_common/once/futex.rs
@@ -128,7 +128,8 @@ impl Once {
RUNNING | QUEUED => {
// Set the state to QUEUED if it is not already.
if state == RUNNING
- && let Err(new) = self.state.compare_exchange_weak(RUNNING, QUEUED, Relaxed, Acquire)
+ && let Err(new) =
+ self.state.compare_exchange_weak(RUNNING, QUEUED, Relaxed, Acquire)
{
state = new;
continue;
diff --git a/library/std/src/sys_common/thread.rs b/library/std/src/sys_common/thread.rs
index 76466b2b3..8f5624bbc 100644
--- a/library/std/src/sys_common/thread.rs
+++ b/library/std/src/sys_common/thread.rs
@@ -8,7 +8,7 @@ pub fn min_stack() -> usize {
0 => {}
n => return n - 1,
}
- let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok());
+ let amt = env::var_os("RUST_MIN_STACK").and_then(|s| s.to_str().and_then(|s| s.parse().ok()));
let amt = amt.unwrap_or(imp::DEFAULT_MIN_STACK_SIZE);
// 0 is our sentinel value, so ensure that we'll never see 0 after
diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs
index a07bbe6d7..28a426648 100644
--- a/library/std/src/sys_common/wtf8/tests.rs
+++ b/library/std/src/sys_common/wtf8/tests.rs
@@ -1,5 +1,4 @@
use super::*;
-use crate::borrow::Cow;
#[test]
fn code_point_from_u32() {
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 4097eb554..849893780 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -548,10 +548,6 @@ impl Builder {
let main = Box::new(main);
// SAFETY: dynamic size and alignment of the Box remain the same. See below for why the
// lifetime change is justified.
- #[cfg(bootstrap)]
- let main =
- unsafe { mem::transmute::<Box<dyn FnOnce() + 'a>, Box<dyn FnOnce() + 'static>>(main) };
- #[cfg(not(bootstrap))]
let main = unsafe { Box::from_raw(Box::into_raw(main) as *mut (dyn FnOnce() + 'static)) };
Ok(JoinInner {
@@ -1585,6 +1581,7 @@ impl<'scope, T> JoinInner<'scope, T> {
/// [`thread::Builder::spawn`]: Builder::spawn
/// [`thread::spawn`]: spawn
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(target_os = "teeos", must_use)]
pub struct JoinHandle<T>(JoinInner<'static, T>);
#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]
diff --git a/library/std/tests/common/mod.rs b/library/std/tests/common/mod.rs
index 358c2c3f9..1aad6549e 100644
--- a/library/std/tests/common/mod.rs
+++ b/library/std/tests/common/mod.rs
@@ -1,17 +1,17 @@
#![allow(unused)]
+use rand::RngCore;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::thread;
-use rand::RngCore;
/// Copied from `std::test_helpers::test_rng`, since these tests rely on the
/// seed not being the same for every RNG invocation too.
#[track_caller]
pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
use core::hash::{BuildHasher, Hash, Hasher};
- let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
+ let mut hasher = std::hash::RandomState::new().build_hasher();
core::panic::Location::caller().hash(&mut hasher);
let hc64 = hasher.finish();
let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();