diff options
Diffstat (limited to 'src/libstd')
38 files changed, 658 insertions, 430 deletions
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 41e778b6a4c..9e3d9af5ba2 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -21,6 +21,7 @@ libc = { version = "0.2.44", default-features = false, features = ['rustc-dep-of compiler_builtins = { version = "0.1.1" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } unwind = { path = "../libunwind" } +rustc-demangle = { version = "0.1.10", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = "0.6.1" @@ -39,7 +40,7 @@ rustc_tsan = { path = "../librustc_tsan" } dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] } [target.x86_64-fortanix-unknown-sgx.dependencies] -fortanix-sgx-abi = { version = "0.3.1", features = ['rustc-dep-of-std'] } +fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] } [build-dependencies] cc = "1.0" diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 55a1a75d049..9c994d29202 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -354,7 +354,7 @@ const DISPLACEMENT_THRESHOLD: usize = 128; /// *stat += random_stat_buff(); /// ``` /// -/// The easiest way to use `HashMap` with a custom type as key is to derive [`Eq`] and [`Hash`]. +/// The easiest way to use `HashMap` with a custom key type is to derive [`Eq`] and [`Hash`]. /// We must also derive [`PartialEq`]. /// /// [`Eq`]: ../../std/cmp/trait.Eq.html diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 479e6dccb90..7195175db28 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -740,6 +740,7 @@ impl<K, V> RawTable<K, V> { } } + #[inline] fn new_internal( capacity: usize, fallibility: Fallibility, @@ -755,12 +756,14 @@ impl<K, V> RawTable<K, V> { /// Tries to create a new raw table from a given capacity. If it cannot allocate, /// it returns with AllocErr. + #[inline] pub fn try_new(capacity: usize) -> Result<RawTable<K, V>, CollectionAllocErr> { Self::new_internal(capacity, Fallible) } /// Creates a new raw table from a given capacity. All buckets are /// initially empty. + #[inline] pub fn new(capacity: usize) -> RawTable<K, V> { match Self::new_internal(capacity, Infallible) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 7d17aaf2f26..209343444a0 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -253,10 +253,10 @@ impl f32 { unsafe { intrinsics::fmaf32(self, a, b) } } - /// Calculates Euclidean division, the matching method for `mod_euc`. + /// Calculates Euclidean division, the matching method for `rem_euclid`. /// /// This computes the integer `n` such that - /// `self = n * rhs + self.mod_euc(rhs)`. + /// `self = n * rhs + self.rem_euclid(rhs)`. /// In other words, the result is `self / rhs` rounded to the integer `n` /// such that `self >= n * rhs`. /// @@ -266,14 +266,14 @@ impl f32 { /// #![feature(euclidean_division)] /// let a: f32 = 7.0; /// let b = 4.0; - /// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0 - /// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0 - /// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0 - /// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 /// ``` #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] - pub fn div_euc(self, rhs: f32) -> f32 { + pub fn div_euclid(self, rhs: f32) -> f32 { let q = (self / rhs).trunc(); if self % rhs < 0.0 { return if rhs > 0.0 { q - 1.0 } else { q + 1.0 } @@ -281,7 +281,7 @@ impl f32 { q } - /// Calculates the Euclidean modulo (self mod rhs), which is never negative. + /// Calculates the least nonnegative remainder of `self (mod rhs)`. /// /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in /// most cases. However, due to a floating point round-off error it can @@ -289,7 +289,7 @@ impl f32 { /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. /// This result is not an element of the function's codomain, but it is the /// closest floating point number in the real numbers and thus fulfills the - /// property `self == self.div_euc(rhs) * rhs + self.mod_euc(rhs)` + /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` /// approximatively. /// /// # Examples @@ -298,16 +298,16 @@ impl f32 { /// #![feature(euclidean_division)] /// let a: f32 = 7.0; /// let b = 4.0; - /// assert_eq!(a.mod_euc(b), 3.0); - /// assert_eq!((-a).mod_euc(b), 1.0); - /// assert_eq!(a.mod_euc(-b), 3.0); - /// assert_eq!((-a).mod_euc(-b), 1.0); + /// assert_eq!(a.rem_euclid(b), 3.0); + /// assert_eq!((-a).rem_euclid(b), 1.0); + /// assert_eq!(a.rem_euclid(-b), 3.0); + /// assert_eq!((-a).rem_euclid(-b), 1.0); /// // limitation due to round-off error - /// assert!((-std::f32::EPSILON).mod_euc(3.0) != 0.0); + /// assert!((-std::f32::EPSILON).rem_euclid(3.0) != 0.0); /// ``` #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] - pub fn mod_euc(self, rhs: f32) -> f32 { + pub fn rem_euclid(self, rhs: f32) -> f32 { let r = self % rhs; if r < 0.0 { r + rhs.abs() @@ -550,7 +550,8 @@ impl f32 { #[inline] #[rustc_deprecated(since = "1.10.0", reason = "you probably meant `(self - other).abs()`: \ - this operation is `(self - other).max(0.0)` (also \ + this operation is `(self - other).max(0.0)` \ + except that `abs_sub` also propagates NaNs (also \ known as `fdimf` in C). If you truly need the positive \ difference, consider using that expression or the C function \ `fdimf`, depending on how you wish to handle NaN (please consider \ diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index c800763167f..b73a67ed9d8 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -229,10 +229,10 @@ impl f64 { unsafe { intrinsics::fmaf64(self, a, b) } } - /// Calculates Euclidean division, the matching method for `mod_euc`. + /// Calculates Euclidean division, the matching method for `rem_euclid`. /// /// This computes the integer `n` such that - /// `self = n * rhs + self.mod_euc(rhs)`. + /// `self = n * rhs + self.rem_euclid(rhs)`. /// In other words, the result is `self / rhs` rounded to the integer `n` /// such that `self >= n * rhs`. /// @@ -242,14 +242,14 @@ impl f64 { /// #![feature(euclidean_division)] /// let a: f64 = 7.0; /// let b = 4.0; - /// assert_eq!(a.div_euc(b), 1.0); // 7.0 > 4.0 * 1.0 - /// assert_eq!((-a).div_euc(b), -2.0); // -7.0 >= 4.0 * -2.0 - /// assert_eq!(a.div_euc(-b), -1.0); // 7.0 >= -4.0 * -1.0 - /// assert_eq!((-a).div_euc(-b), 2.0); // -7.0 >= -4.0 * 2.0 + /// assert_eq!(a.div_euclid(b), 1.0); // 7.0 > 4.0 * 1.0 + /// assert_eq!((-a).div_euclid(b), -2.0); // -7.0 >= 4.0 * -2.0 + /// assert_eq!(a.div_euclid(-b), -1.0); // 7.0 >= -4.0 * -1.0 + /// assert_eq!((-a).div_euclid(-b), 2.0); // -7.0 >= -4.0 * 2.0 /// ``` #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] - pub fn div_euc(self, rhs: f64) -> f64 { + pub fn div_euclid(self, rhs: f64) -> f64 { let q = (self / rhs).trunc(); if self % rhs < 0.0 { return if rhs > 0.0 { q - 1.0 } else { q + 1.0 } @@ -257,7 +257,7 @@ impl f64 { q } - /// Calculates the Euclidean modulo (self mod rhs), which is never negative. + /// Calculates the least nonnegative remainder of `self (mod rhs)`. /// /// In particular, the return value `r` satisfies `0.0 <= r < rhs.abs()` in /// most cases. However, due to a floating point round-off error it can @@ -265,7 +265,7 @@ impl f64 { /// `self` is much smaller than `rhs.abs()` in magnitude and `self < 0.0`. /// This result is not an element of the function's codomain, but it is the /// closest floating point number in the real numbers and thus fulfills the - /// property `self == self.div_euc(rhs) * rhs + self.mod_euc(rhs)` + /// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)` /// approximatively. /// /// # Examples @@ -274,16 +274,16 @@ impl f64 { /// #![feature(euclidean_division)] /// let a: f64 = 7.0; /// let b = 4.0; - /// assert_eq!(a.mod_euc(b), 3.0); - /// assert_eq!((-a).mod_euc(b), 1.0); - /// assert_eq!(a.mod_euc(-b), 3.0); - /// assert_eq!((-a).mod_euc(-b), 1.0); + /// assert_eq!(a.rem_euclid(b), 3.0); + /// assert_eq!((-a).rem_euclid(b), 1.0); + /// assert_eq!(a.rem_euclid(-b), 3.0); + /// assert_eq!((-a).rem_euclid(-b), 1.0); /// // limitation due to round-off error - /// assert!((-std::f64::EPSILON).mod_euc(3.0) != 0.0); + /// assert!((-std::f64::EPSILON).rem_euclid(3.0) != 0.0); /// ``` #[inline] #[unstable(feature = "euclidean_division", issue = "49048")] - pub fn mod_euc(self, rhs: f64) -> f64 { + pub fn rem_euclid(self, rhs: f64) -> f64 { let r = self % rhs; if r < 0.0 { r + rhs.abs() @@ -491,7 +491,8 @@ impl f64 { #[inline] #[rustc_deprecated(since = "1.10.0", reason = "you probably meant `(self - other).abs()`: \ - this operation is `(self - other).max(0.0)` (also \ + this operation is `(self - other).max(0.0)` \ + except that `abs_sub` also propagates NaNs (also \ known as `fdim` in C). If you truly need the positive \ difference, consider using that expression or the C function \ `fdim`, depending on how you wish to handle NaN (please consider \ diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index edcfdd9e534..35ae4939249 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1729,7 +1729,7 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> { /// limited to just these cases: /// /// * `path` does not exist. -/// * A component in path is not a directory. +/// * A non-final component in path is not a directory. /// /// # Examples /// diff --git a/src/libstd/future.rs b/src/libstd/future.rs index d5e6cab948b..3379be79186 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -43,7 +43,7 @@ impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {} impl<T: Generator<Yield = ()>> Future for GenFuture<T> { type Output = T::Return; fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll<Self::Output> { - set_task_waker(lw, || match unsafe { Pin::get_mut_unchecked(self).0.resume() } { + set_task_waker(lw, || match unsafe { Pin::get_unchecked_mut(self).0.resume() } { GeneratorState::Yielded(()) => Poll::Pending, GeneratorState::Complete(x) => Poll::Ready(x), }) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 7ede050da6c..7aaf89cd0ff 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -294,7 +294,7 @@ impl<R: Seek> Seek for BufReader<R> { /// `.into_inner()` immediately after a seek yields the underlying reader /// at the same position. /// - /// To seek without discarding the internal buffer, use [`Seek::seek_relative`]. + /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`]. /// /// See [`std::io::Seek`] for more details. /// @@ -303,6 +303,9 @@ impl<R: Seek> Seek for BufReader<R> { /// seeks will be performed instead of one. If the second seek returns /// `Err`, the underlying reader will be left at the same position it would /// have if you called `seek` with `SeekFrom::Current(0)`. + /// + /// [`BufReader::seek_relative`]: struct.BufReader.html#method.seek_relative + /// [`std::io::Seek`]: trait.Seek.html fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { let result: u64; if let SeekFrom::Current(n) = pos { diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index d3844ebe19e..324852355b0 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -225,6 +225,9 @@ impl From<ErrorKind> for Error { /// let error = Error::from(not_found); /// assert_eq!("entity not found", format!("{}", error)); /// ``` + /// + /// [`ErrorKind`]: ../../std/io/enum.ErrorKind.html + /// [`Error`]: ../../std/io/struct.Error.html #[inline] fn from(kind: ErrorKind) -> Error { Error { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index dc97701d889..5137a9432ae 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -271,6 +271,7 @@ use cmp; use fmt; +use slice; use str; use memchr; use ptr; @@ -1936,18 +1937,6 @@ impl<T: BufRead> BufRead for Take<T> { } } -fn read_one_byte(reader: &mut dyn Read) -> Option<Result<u8>> { - let mut buf = [0]; - loop { - return match reader.read(&mut buf) { - Ok(0) => None, - Ok(..) => Some(Ok(buf[0])), - Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, - Err(e) => Some(Err(e)), - }; - } -} - /// An iterator over `u8` values of a reader. /// /// This struct is generally created by calling [`bytes`] on a reader. @@ -1965,7 +1954,15 @@ impl<R: Read> Iterator for Bytes<R> { type Item = Result<u8>; fn next(&mut self) -> Option<Result<u8>> { - read_one_byte(&mut self.inner) + let mut byte = 0; + loop { + return match self.inner.read(slice::from_mut(&mut byte)) { + Ok(0) => None, + Ok(..) => Some(Ok(byte)), + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => Some(Err(e)), + }; + } } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0febbe5694b..4a693bffddf 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -222,6 +222,7 @@ #![no_std] #![deny(missing_docs)] +#![deny(intra_doc_link_resolution_failure)] #![deny(missing_debug_implementations)] // Tell the compiler to link to either panic_abort or panic_unwind @@ -250,6 +251,7 @@ #![feature(cfg_target_vendor)] #![feature(char_error_internals)] #![feature(compiler_builtins_lib)] +#![feature(concat_idents)] #![feature(const_int_ops)] #![feature(const_ip)] #![feature(const_raw_ptr_deref)] @@ -271,7 +273,6 @@ #![feature(libc)] #![feature(link_args)] #![feature(linkage)] -#![cfg_attr(not(stage0), feature(min_const_unsafe_fn))] #![feature(needs_panic_runtime)] #![feature(never_type)] #![feature(nll)] @@ -280,7 +281,6 @@ #![feature(optin_builtin_traits)] #![feature(panic_internals)] #![feature(panic_unwind)] -#![feature(pin)] #![feature(prelude_import)] #![feature(ptr_internals)] #![feature(raw)] @@ -314,7 +314,7 @@ #![feature(alloc_layout_extra)] #![feature(maybe_uninit)] #![cfg_attr(target_env = "sgx", feature(global_asm, range_contains, slice_index_methods, - decl_macro, coerce_unsized))] + decl_macro, coerce_unsized, sgx_platform))] #![default_lib_allocator] @@ -339,6 +339,7 @@ pub use core::{unreachable, unimplemented, write, writeln, try}; extern crate alloc as alloc_crate; #[doc(masked)] extern crate libc; +extern crate rustc_demangle; // We always need an unwinder currently for backtraces #[doc(masked)] @@ -431,7 +432,7 @@ pub use alloc_crate::borrow; pub use alloc_crate::fmt; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::format; -#[unstable(feature = "pin", issue = "49150")] +#[stable(feature = "pin", since = "1.33.0")] pub use core::pin; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc_crate::slice; diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 5aa043b0fcb..347e795c4f7 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -729,6 +729,9 @@ impl TcpListener { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { + // On WASM, `TcpStream` is uninhabited (as it's unsupported) and so + // the `a` variable here is technically unused. + #[cfg_attr(target_arch = "wasm32", allow(unused_variables))] self.0.accept().map(|(a, b)| (TcpStream(a), b)) } diff --git a/src/libstd/os/fortanix_sgx/mod.rs b/src/libstd/os/fortanix_sgx/mod.rs new file mode 100644 index 00000000000..825e7f359d6 --- /dev/null +++ b/src/libstd/os/fortanix_sgx/mod.rs @@ -0,0 +1,67 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Functionality specific to the `x86_64-fortanix-unknown-sgx` target. +//! +//! This includes functions to deal with memory isolation, usercalls, and the +//! SGX instruction set. + +#![deny(missing_docs, missing_debug_implementations)] +#![unstable(feature = "sgx_platform", issue = "56975")] + +/// Low-level interfaces to usercalls. See the [ABI documentation] for more +/// information. +/// +/// [ABI documentation]: https://docs.rs/fortanix-sgx-abi/ +pub mod usercalls { + pub use sys::abi::usercalls::*; + + /// Primitives for allocating memory in userspace as well as copying data + /// to and from user memory. + pub mod alloc { + pub use sys::abi::usercalls::alloc; + } + + /// Lowest-level interfaces to usercalls and usercall ABI type definitions. + pub mod raw { + use sys::abi::usercalls::raw::invoke_with_usercalls; + pub use sys::abi::usercalls::raw::do_usercall; + pub use sys::abi::usercalls::raw::{accept_stream, alloc, async_queues, bind_stream, close, + connect_stream, exit, flush, free, insecure_time, + launch_thread, read, read_alloc, send, wait, write}; + + macro_rules! define_usercallnrs { + ($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:ty)*; )*) => { + /// Usercall numbers as per the ABI. + #[repr(C)] + #[unstable(feature = "sgx_platform", issue = "56975")] + #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] + #[allow(missing_docs)] + pub enum UsercallNrs { + $($f,)* + } + }; + } + invoke_with_usercalls!(define_usercallnrs); + + // fortanix-sgx-abi re-exports + pub use sys::abi::usercalls::raw::{ByteBuffer, FifoDescriptor, Return, Usercall}; + pub use sys::abi::usercalls::raw::Error; + pub use sys::abi::usercalls::raw::{EV_RETURNQ_NOT_EMPTY, EV_UNPARK, EV_USERCALLQ_NOT_FULL, + FD_STDERR, FD_STDIN, FD_STDOUT, RESULT_SUCCESS, + USERCALL_USER_DEFINED, WAIT_INDEFINITE, WAIT_NO}; + pub use sys::abi::usercalls::raw::{Fd, Result, Tcs}; + } +} + +/// Functions for querying mapping information for pointers. +pub mod mem { + pub use sys::abi::mem::*; +} diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs index 1cb9799ff3c..ba5b938ed4c 100644 --- a/src/libstd/os/mod.rs +++ b/src/libstd/os/mod.rs @@ -29,25 +29,10 @@ cfg_if! { #[doc(cfg(target_os = "linux"))] pub mod linux; - } else { - // If we're not documenting libstd then we just expose everything as we - // otherwise would. - - #[cfg(target_os = "android")] pub mod android; - #[cfg(target_os = "bitrig")] pub mod bitrig; - #[cfg(target_os = "dragonfly")] pub mod dragonfly; - #[cfg(target_os = "freebsd")] pub mod freebsd; - #[cfg(target_os = "haiku")] pub mod haiku; - #[cfg(target_os = "ios")] pub mod ios; - #[cfg(target_os = "macos")] pub mod macos; - #[cfg(target_os = "netbsd")] pub mod netbsd; - #[cfg(target_os = "openbsd")] pub mod openbsd; - #[cfg(target_os = "solaris")] pub mod solaris; - #[cfg(target_os = "emscripten")] pub mod emscripten; - #[cfg(target_os = "fuchsia")] pub mod fuchsia; - #[cfg(target_os = "hermit")] pub mod hermit; + // If we're not documenting libstd then we just expose the main modules + // as we otherwise would. #[cfg(any(target_os = "redox", unix))] #[stable(feature = "rust1", since = "1.0.0")] @@ -63,4 +48,19 @@ cfg_if! { } } +#[cfg(target_os = "android")] pub mod android; +#[cfg(target_os = "bitrig")] pub mod bitrig; +#[cfg(target_os = "dragonfly")] pub mod dragonfly; +#[cfg(target_os = "freebsd")] pub mod freebsd; +#[cfg(target_os = "haiku")] pub mod haiku; +#[cfg(target_os = "ios")] pub mod ios; +#[cfg(target_os = "macos")] pub mod macos; +#[cfg(target_os = "netbsd")] pub mod netbsd; +#[cfg(target_os = "openbsd")] pub mod openbsd; +#[cfg(target_os = "solaris")] pub mod solaris; +#[cfg(target_os = "emscripten")] pub mod emscripten; +#[cfg(target_os = "fuchsia")] pub mod fuchsia; +#[cfg(target_os = "hermit")] pub mod hermit; +#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] pub mod fortanix_sgx; + pub mod raw; diff --git a/src/libstd/os/raw/mod.rs b/src/libstd/os/raw/mod.rs index 95faf3a5dd6..05f30f2881a 100644 --- a/src/libstd/os/raw/mod.rs +++ b/src/libstd/os/raw/mod.rs @@ -27,6 +27,10 @@ all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), all(target_os = "l4re", target_arch = "x86_64"), + all(target_os = "freebsd", any(target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64")), all(target_os = "netbsd", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")), @@ -42,6 +46,10 @@ all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), all(target_os = "l4re", target_arch = "x86_64"), + all(target_os = "freebsd", any(target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64")), all(target_os = "netbsd", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")), diff --git a/src/libstd/path.rs b/src/libstd/path.rs index b882442dd2f..df05eb7d604 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1461,7 +1461,7 @@ impl From<String> for PathBuf { } } -#[stable(feature = "path_from_str", since = "1.26.0")] +#[stable(feature = "path_from_str", since = "1.32.0")] impl FromStr for PathBuf { type Err = ParseError; diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 9e957bd87d7..fdaf2a821fa 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -73,18 +73,3 @@ fn lang_start<T: ::process::Termination + 'static> { lang_start_internal(&move || main().report(), argc, argv) } - -/// Function used for reverting changes to the main stack before setrlimit(). -/// This is POSIX (non-Linux) specific and unlikely to be directly stabilized. -#[unstable(feature = "rustc_stack_internals", issue = "0")] -pub unsafe fn deinit_stack_guard() { - ::sys::thread::guard::deinit(); -} - -/// Function used for resetting the main stack guard address after setrlimit(). -/// This is POSIX specific and unlikely to be directly stabilized. -#[unstable(feature = "rustc_stack_internals", issue = "0")] -pub unsafe fn update_stack_guard() { - let main_guard = ::sys::thread::guard::init(); - ::sys_common::thread_info::reset_guard(main_guard); -} diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs index 177321439d8..a64e0f06849 100644 --- a/src/libstd/sys/cloudabi/thread.rs +++ b/src/libstd/sys/cloudabi/thread.rs @@ -121,7 +121,6 @@ pub mod guard { pub unsafe fn init() -> Option<Guard> { None } - pub unsafe fn deinit() {} } fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs index 04c47aeb827..625202e5604 100644 --- a/src/libstd/sys/mod.rs +++ b/src/libstd/sys/mod.rs @@ -65,7 +65,7 @@ cfg_if! { if #[cfg(any(unix, target_os = "redox"))] { // On unix we'll document what's already available pub use self::ext as unix_ext; - } else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] { + } else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32", target_env = "sgx"))] { // On CloudABI and wasm right now the module below doesn't compile // (missing things in `libc` which is empty) so just omit everything // with an empty module @@ -86,7 +86,7 @@ cfg_if! { // On windows we'll just be documenting what's already available #[allow(missing_docs)] pub use self::ext as windows_ext; - } else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] { + } else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32", target_env = "sgx"))] { // On CloudABI and wasm right now the shim below doesn't compile, so // just omit it #[unstable(issue = "0", feature = "std_internals")] diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index ff861805382..ca014fd576b 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -92,5 +92,4 @@ pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option<Guard> { None } pub unsafe fn init() -> Option<Guard> { None } - pub unsafe fn deinit() {} } diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S index 4d5cc02e11e..49ede0674ce 100644 --- a/src/libstd/sys/sgx/abi/entry.S +++ b/src/libstd/sys/sgx/abi/entry.S @@ -56,6 +56,14 @@ IMAGE_BASE: globvar CFGDATA_BASE 8 /* Non-zero if debugging is enabled, zero otherwise */ globvar DEBUG 1 + /* The base address (relative to enclave start) of the enclave text section */ + globvar TEXT_BASE 8 + /* The size in bytes of enclacve text section */ + globvar TEXT_SIZE 8 + /* The base address (relative to enclave start) of the enclave EH_FRM_HDR section */ + globvar EH_FRM_HDR_BASE 8 + /* The size in bytes of enclacve EH_FRM_HDR section */ + globvar EH_FRM_HDR_SIZE 8 .Lreentry_panic_msg: .asciz "Re-entered panicked enclave!" diff --git a/src/libstd/sys/sgx/abi/mem.rs b/src/libstd/sys/sgx/abi/mem.rs index bf32c712216..11eb64606c4 100644 --- a/src/libstd/sys/sgx/abi/mem.rs +++ b/src/libstd/sys/sgx/abi/mem.rs @@ -10,13 +10,13 @@ // Do not remove inline: will result in relocation failure #[inline(always)] -pub unsafe fn rel_ptr<T>(offset: u64) -> *const T { +pub(crate) unsafe fn rel_ptr<T>(offset: u64) -> *const T { (image_base() + offset) as *const T } // Do not remove inline: will result in relocation failure #[inline(always)] -pub unsafe fn rel_ptr_mut<T>(offset: u64) -> *mut T { +pub(crate) unsafe fn rel_ptr_mut<T>(offset: u64) -> *mut T { (image_base() + offset) as *mut T } @@ -34,6 +34,17 @@ fn image_base() -> u64 { base } +/// Returns `true` if the specified memory range is in the enclave. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub fn is_enclave_range(p: *const u8, len: usize) -> bool { + let start=p as u64; + let end=start + (len as u64); + start >= image_base() && + end <= image_base() + (unsafe { ENCLAVE_SIZE } as u64) // unsafe ok: link-time constant +} + +/// Returns `true` if the specified memory range is in userspace. +#[unstable(feature = "sgx_platform", issue = "56975")] pub fn is_user_range(p: *const u8, len: usize) -> bool { let start=p as u64; let end=start + (len as u64); diff --git a/src/libstd/sys/sgx/abi/mod.rs b/src/libstd/sys/sgx/abi/mod.rs index 069cca3b98e..18ba221af5a 100644 --- a/src/libstd/sys/sgx/abi/mod.rs +++ b/src/libstd/sys/sgx/abi/mod.rs @@ -13,10 +13,10 @@ use io::Write; // runtime features mod reloc; -mod mem; pub(super) mod panic; // library features +pub mod mem; pub mod thread; pub mod tls; #[macro_use] diff --git a/src/libstd/sys/sgx/abi/usercalls/alloc.rs b/src/libstd/sys/sgx/abi/usercalls/alloc.rs index 64968a9970c..f1689091eb5 100644 --- a/src/libstd/sys/sgx/abi/usercalls/alloc.rs +++ b/src/libstd/sys/sgx/abi/usercalls/alloc.rs @@ -10,7 +10,7 @@ #![allow(unused)] -use ptr; +use ptr::{self, NonNull}; use mem; use cell::UnsafeCell; use slice; @@ -39,39 +39,78 @@ use super::super::mem::is_user_range; /// as vtable pointers) must not be leaked for confidentiality reasons. /// /// Non-exhaustive list of specific requirements for reading from userspace: -/// * Any bit pattern is valid for this type (no `enum`s). There can be no +/// * **Any bit pattern is valid** for this type (no `enum`s). There can be no /// guarantee that the value correctly adheres to the expectations of the /// type, so any value must be valid for this type. /// /// Non-exhaustive list of specific requirements for writing to userspace: -/// * No pointers to enclave memory. Memory addresses of data in enclave memory -/// must not be leaked for confidentiality reasons. -/// * No internal padding. Padding might contain previously-initialized secret -/// data stored at that memory location and must not be leaked for +/// * **No pointers to enclave memory.** Memory addresses of data in enclave +/// memory must not be leaked for confidentiality reasons. +/// * **No internal padding.** Padding might contain previously-initialized +/// secret data stored at that memory location and must not be leaked for /// confidentiality reasons. +#[unstable(feature = "sgx_platform", issue = "56975")] pub unsafe trait UserSafeSized: Copy + Sized {} +#[unstable(feature = "sgx_platform", issue = "56975")] unsafe impl UserSafeSized for u8 {} +#[unstable(feature = "sgx_platform", issue = "56975")] unsafe impl<T> UserSafeSized for FifoDescriptor<T> {} +#[unstable(feature = "sgx_platform", issue = "56975")] unsafe impl UserSafeSized for ByteBuffer {} +#[unstable(feature = "sgx_platform", issue = "56975")] unsafe impl UserSafeSized for Usercall {} +#[unstable(feature = "sgx_platform", issue = "56975")] unsafe impl UserSafeSized for Return {} +#[unstable(feature = "sgx_platform", issue = "56975")] unsafe impl<T: UserSafeSized> UserSafeSized for [T; 2] {} /// A type that can be represented in memory as one or more `UserSafeSized`s. +#[unstable(feature = "sgx_platform", issue = "56975")] pub unsafe trait UserSafe { - unsafe fn align_of() -> usize; + /// Equivalent to `mem::align_of::<Self>`. + fn align_of() -> usize; + /// Construct a pointer to `Self` given a memory range in user space. + /// /// NB. This takes a size, not a length! - unsafe fn from_raw_sized_unchecked(ptr: *const u8, size: usize) -> *const Self; + /// + /// # Safety + /// The caller must ensure the memory range is in user memory, is the + /// correct size and is correctly aligned and points to the right type. + unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self; + /// Construct a pointer to `Self` given a memory range. + /// /// NB. This takes a size, not a length! - unsafe fn from_raw_sized(ptr: *const u8, size: usize) -> *const Self { + /// + /// # Safety + /// The caller must ensure the memory range points to the correct type. + /// + /// # Panics + /// This function panics if: + /// + /// * The pointer is not aligned + /// * The pointer is null + /// * The pointed-to range is not in user memory + unsafe fn from_raw_sized(ptr: *mut u8, size: usize) -> NonNull<Self> { let ret = Self::from_raw_sized_unchecked(ptr, size); Self::check_ptr(ret); - ret + NonNull::new_unchecked(ret as _) } + /// Check if a pointer may point to Self in user memory. + /// + /// # Safety + /// The caller must ensure the memory range points to the correct type and + /// length (if this is a slice). + /// + /// # Panics + /// This function panics if: + /// + /// * The pointer is not aligned + /// * The pointer is null + /// * The pointed-to range is not in user memory unsafe fn check_ptr(ptr: *const Self) { let is_aligned = |p| -> bool { 0 == (p as usize) & (Self::align_of() - 1) @@ -83,27 +122,29 @@ pub unsafe trait UserSafe { } } +#[unstable(feature = "sgx_platform", issue = "56975")] unsafe impl<T: UserSafeSized> UserSafe for T { - unsafe fn align_of() -> usize { + fn align_of() -> usize { mem::align_of::<T>() } - unsafe fn from_raw_sized_unchecked(ptr: *const u8, size: usize) -> *const Self { + unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self { assert_eq!(size, mem::size_of::<T>()); ptr as _ } } +#[unstable(feature = "sgx_platform", issue = "56975")] unsafe impl<T: UserSafeSized> UserSafe for [T] { - unsafe fn align_of() -> usize { + fn align_of() -> usize { mem::align_of::<T>() } - unsafe fn from_raw_sized_unchecked(ptr: *const u8, size: usize) -> *const Self { + unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self { let elem_size = mem::size_of::<T>(); assert_eq!(size % elem_size, 0); let len = size / elem_size; - slice::from_raw_parts(ptr as _, len) + slice::from_raw_parts_mut(ptr as _, len) } } @@ -111,14 +152,40 @@ unsafe impl<T: UserSafeSized> UserSafe for [T] { /// to `&T` in enclave memory. Access to the memory is only allowed by copying /// to avoid TOCTTOU issues. After copying, code should make sure to completely /// check the value before use. +/// +/// It is also possible to obtain a mutable reference `&mut UserRef<T>`. Unlike +/// regular mutable references, these are not exclusive. Userspace may always +/// write to the backing memory at any time, so it can't be assumed that there +/// the pointed-to memory is uniquely borrowed. The two different refence types +/// are used solely to indicate intent: a mutable reference is for writing to +/// user memory, an immutable reference for reading from user memory. +#[unstable(feature = "sgx_platform", issue = "56975")] pub struct UserRef<T: ?Sized>(UnsafeCell<T>); /// An owned type in userspace memory. `User<T>` is equivalent to `Box<T>` in /// enclave memory. Access to the memory is only allowed by copying to avoid /// TOCTTOU issues. The user memory will be freed when the value is dropped. /// After copying, code should make sure to completely check the value before /// use. -pub struct User<T: UserSafe + ?Sized>(*mut UserRef<T>); +#[unstable(feature = "sgx_platform", issue = "56975")] +pub struct User<T: UserSafe + ?Sized>(NonNull<UserRef<T>>); + +trait NewUserRef<T: ?Sized> { + unsafe fn new_userref(v: T) -> Self; +} + +impl<T: ?Sized> NewUserRef<*mut T> for NonNull<UserRef<T>> { + unsafe fn new_userref(v: *mut T) -> Self { + NonNull::new_unchecked(v as _) + } +} +impl<T: ?Sized> NewUserRef<NonNull<T>> for NonNull<UserRef<T>> { + unsafe fn new_userref(v: NonNull<T>) -> Self { + NonNull::new_userref(v.as_ptr()) + } +} + +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T: ?Sized> User<T> where T: UserSafe { // This function returns memory that is practically uninitialized, but is // not considered "unspecified" or "undefined" for purposes of an @@ -127,24 +194,28 @@ impl<T: ?Sized> User<T> where T: UserSafe { fn new_uninit_bytes(size: usize) -> Self { unsafe { let ptr = super::alloc(size, T::align_of()).expect("User memory allocation failed"); - User(T::from_raw_sized(ptr as _, size) as _) + User(NonNull::new_userref(T::from_raw_sized(ptr as _, size))) } } + /// Copy `val` into freshly allocated space in user memory. pub fn new_from_enclave(val: &T) -> Self { unsafe { let ret = Self::new_uninit_bytes(mem::size_of_val(val)); ptr::copy( val as *const T as *const u8, - ret.0 as *mut T as *mut u8, + ret.0.as_ptr() as *mut u8, mem::size_of_val(val) ); ret } } - /// Create an owned `User<T>` from a raw pointer. The pointer should be - /// freeable with the `free` usercall and the alignment of `T`. + /// Create an owned `User<T>` from a raw pointer. + /// + /// # Safety + /// The caller must ensure `ptr` points to `T`, is freeable with the `free` + /// usercall and the alignment of `T`, and is uniquely owned. /// /// # Panics /// This function panics if: @@ -154,7 +225,7 @@ impl<T: ?Sized> User<T> where T: UserSafe { /// * The pointed-to range is not in user memory pub unsafe fn from_raw(ptr: *mut T) -> Self { T::check_ptr(ptr); - User(ptr as _) + User(NonNull::new_userref(ptr)) } /// Convert this value into a raw pointer. The value will no longer be @@ -162,24 +233,31 @@ impl<T: ?Sized> User<T> where T: UserSafe { pub fn into_raw(self) -> *mut T { let ret = self.0; mem::forget(self); - ret as _ + ret.as_ptr() as _ } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T> User<T> where T: UserSafe { + /// Allocate space for `T` in user memory. pub fn uninitialized() -> Self { Self::new_uninit_bytes(mem::size_of::<T>()) } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T> User<[T]> where [T]: UserSafe { + /// Allocate space for a `[T]` of `n` elements in user memory. pub fn uninitialized(n: usize) -> Self { Self::new_uninit_bytes(n * mem::size_of::<T>()) } /// Create an owned `User<[T]>` from a raw thin pointer and a slice length. - /// The pointer should be freeable with the `free` usercall and the - /// alignment of `T`. + /// + /// # Safety + /// The caller must ensure `ptr` points to `len` elements of `T`, is + /// freeable with the `free` usercall and the alignment of `T`, and is + /// uniquely owned. /// /// # Panics /// This function panics if: @@ -188,13 +266,17 @@ impl<T> User<[T]> where [T]: UserSafe { /// * The pointer is null /// * The pointed-to range is not in user memory pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self { - User(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()) as _) + User(NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()))) } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T: ?Sized> UserRef<T> where T: UserSafe { /// Create a `&UserRef<[T]>` from a raw pointer. /// + /// # Safety + /// The caller must ensure `ptr` points to `T`. + /// /// # Panics /// This function panics if: /// @@ -206,7 +288,11 @@ impl<T: ?Sized> UserRef<T> where T: UserSafe { &*(ptr as *const Self) } - /// Create a `&mut UserRef<[T]>` from a raw pointer. + /// Create a `&mut UserRef<[T]>` from a raw pointer. See the struct + /// documentation for the nuances regarding a `&mut UserRef<T>`. + /// + /// # Safety + /// The caller must ensure `ptr` points to `T`. /// /// # Panics /// This function panics if: @@ -219,6 +305,8 @@ impl<T: ?Sized> UserRef<T> where T: UserSafe { &mut*(ptr as *mut Self) } + /// Copy `val` into user memory. + /// /// # Panics /// This function panics if the destination doesn't have the same size as /// the source. This can happen for dynamically-sized types such as slices. @@ -233,6 +321,8 @@ impl<T: ?Sized> UserRef<T> where T: UserSafe { } } + /// Copy the value from user memory and place it into `dest`. + /// /// # Panics /// This function panics if the destination doesn't have the same size as /// the source. This can happen for dynamically-sized types such as slices. @@ -247,24 +337,32 @@ impl<T: ?Sized> UserRef<T> where T: UserSafe { } } + /// Obtain a raw pointer from this reference. pub fn as_raw_ptr(&self) -> *const T { self as *const _ as _ } + /// Obtain a raw pointer from this reference. pub fn as_raw_mut_ptr(&mut self) -> *mut T { self as *mut _ as _ } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T> UserRef<T> where T: UserSafe { + /// Copy the value from user memory into enclave memory. pub fn to_enclave(&self) -> T { unsafe { ptr::read(self.0.get()) } } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T> UserRef<[T]> where [T]: UserSafe { /// Create a `&UserRef<[T]>` from a raw thin pointer and a slice length. /// + /// # Safety + /// The caller must ensure `ptr` points to `n` elements of `T`. + /// /// # Panics /// This function panics if: /// @@ -272,10 +370,15 @@ impl<T> UserRef<[T]> where [T]: UserSafe { /// * The pointer is null /// * The pointed-to range is not in user memory pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self { - &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()) as *const Self) + &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *const Self) } /// Create a `&mut UserRef<[T]>` from a raw thin pointer and a slice length. + /// See the struct documentation for the nuances regarding a + /// `&mut UserRef<T>`. + /// + /// # Safety + /// The caller must ensure `ptr` points to `n` elements of `T`. /// /// # Panics /// This function panics if: @@ -284,21 +387,30 @@ impl<T> UserRef<[T]> where [T]: UserSafe { /// * The pointer is null /// * The pointed-to range is not in user memory pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self { - &mut*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()) as *mut Self) + &mut*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *mut Self) } + /// Obtain a raw pointer to the first element of this user slice. pub fn as_ptr(&self) -> *const T { self.0.get() as _ } + /// Obtain a raw pointer to the first element of this user slice. pub fn as_mut_ptr(&mut self) -> *mut T { self.0.get() as _ } + /// Obtain the number of elements in this user slice. pub fn len(&self) -> usize { unsafe { (*self.0.get()).len() } } + /// Copy the value from user memory and place it into `dest`. Afterwards, + /// `dest` will contain exactly `self.len()` elements. + /// + /// # Panics + /// This function panics if the destination doesn't have the same size as + /// the source. This can happen for dynamically-sized types such as slices. pub fn copy_to_enclave_vec(&self, dest: &mut Vec<T>) { unsafe { if let Some(missing) = self.len().checked_sub(dest.capacity()) { @@ -309,12 +421,14 @@ impl<T> UserRef<[T]> where [T]: UserSafe { } } + /// Copy the value from user memory into a vector in enclave memory. pub fn to_enclave(&self) -> Vec<T> { let mut ret = Vec::with_capacity(self.len()); self.copy_to_enclave_vec(&mut ret); ret } + /// Returns an iterator over the slice. pub fn iter(&self) -> Iter<T> where T: UserSafe // FIXME: should be implied by [T]: UserSafe? { @@ -323,6 +437,7 @@ impl<T> UserRef<[T]> where [T]: UserSafe { } } + /// Returns an iterator that allows modifying each value. pub fn iter_mut(&mut self) -> IterMut<T> where T: UserSafe // FIXME: should be implied by [T]: UserSafe? { @@ -332,8 +447,13 @@ impl<T> UserRef<[T]> where [T]: UserSafe { } } +/// Immutable user slice iterator +/// +/// This struct is created by the `iter` method on `UserRef<[T]>`. +#[unstable(feature = "sgx_platform", issue = "56975")] pub struct Iter<'a, T: 'a + UserSafe>(slice::Iter<'a, T>); +#[unstable(feature = "sgx_platform", issue = "56975")] impl<'a, T: UserSafe> Iterator for Iter<'a, T> { type Item = &'a UserRef<T>; @@ -345,8 +465,13 @@ impl<'a, T: UserSafe> Iterator for Iter<'a, T> { } } +/// Mutable user slice iterator +/// +/// This struct is created by the `iter_mut` method on `UserRef<[T]>`. +#[unstable(feature = "sgx_platform", issue = "56975")] pub struct IterMut<'a, T: 'a + UserSafe>(slice::IterMut<'a, T>); +#[unstable(feature = "sgx_platform", issue = "56975")] impl<'a, T: UserSafe> Iterator for IterMut<'a, T> { type Item = &'a mut UserRef<T>; @@ -358,31 +483,36 @@ impl<'a, T: UserSafe> Iterator for IterMut<'a, T> { } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T: ?Sized> Deref for User<T> where T: UserSafe { type Target = UserRef<T>; fn deref(&self) -> &Self::Target { - unsafe { &*self.0 } + unsafe { &*self.0.as_ptr() } } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T: ?Sized> DerefMut for User<T> where T: UserSafe { fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut*self.0 } + unsafe { &mut*self.0.as_ptr() } } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T: ?Sized> Drop for User<T> where T: UserSafe { fn drop(&mut self) { unsafe { - let ptr = (*self.0).0.get(); + let ptr = (*self.0.as_ptr()).0.get(); super::free(ptr as _, mem::size_of_val(&mut*ptr), T::align_of()); } } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T: CoerceUnsized<U>, U> CoerceUnsized<UserRef<U>> for UserRef<T> {} +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T, I: SliceIndex<[T]>> Index<I> for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe { type Output = UserRef<I::Output>; @@ -394,6 +524,7 @@ impl<T, I: SliceIndex<[T]>> Index<I> for UserRef<[T]> where [T]: UserSafe, I::Ou } } +#[unstable(feature = "sgx_platform", issue = "56975")] impl<T, I: SliceIndex<[T]>> IndexMut<I> for UserRef<[T]> where [T]: UserSafe, I::Output: UserSafe { #[inline] fn index_mut(&mut self, index: I) -> &mut UserRef<I::Output> { @@ -402,3 +533,21 @@ impl<T, I: SliceIndex<[T]>> IndexMut<I> for UserRef<[T]> where [T]: UserSafe, I: } } } + +#[unstable(feature = "sgx_platform", issue = "56975")] +impl UserRef<super::raw::ByteBuffer> { + /// Copy the user memory range pointed to by the user `ByteBuffer` to + /// enclave memory. + /// + /// # Panics + /// This function panics if: + /// + /// * The pointer in the user `ByteBuffer` is null + /// * The pointed-to range in the user `ByteBuffer` is not in user memory + pub fn copy_user_buffer(&self) -> Vec<u8> { + unsafe { + let buf = self.to_enclave(); + User::from_raw_parts(buf.data as _, buf.len).to_enclave() + } + } +} diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs index d1d180e4825..a5066abc144 100644 --- a/src/libstd/sys/sgx/abi/usercalls/mod.rs +++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs @@ -8,22 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use fortanix_sgx_abi::*; - use io::{Error as IoError, Result as IoResult}; use time::Duration; -pub mod alloc; +pub(crate) mod alloc; #[macro_use] -mod raw; +pub(crate) mod raw; -pub(crate) fn copy_user_buffer(buf: &alloc::UserRef<ByteBuffer>) -> Vec<u8> { - unsafe { - let buf = buf.to_enclave(); - alloc::User::from_raw_parts(buf.data as _, buf.len).to_enclave() - } -} +use self::raw::*; +/// Usercall `read`. See the ABI documentation for more information. +#[unstable(feature = "sgx_platform", issue = "56975")] pub fn read(fd: Fd, buf: &mut [u8]) -> IoResult<usize> { unsafe { let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.len()); @@ -33,6 +28,18 @@ pub fn read(fd: Fd, buf: &mut [u8]) -> IoResult<usize> { } } +/// Usercall `read_alloc`. See the ABI documentation for more information. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub fn read_alloc(fd: Fd) -> IoResult<Vec<u8>> { + unsafe { + let mut userbuf = alloc::User::<ByteBuffer>::uninitialized(); + raw::read_alloc(fd, userbuf.as_raw_mut_ptr()).from_sgx_result()?; + Ok(userbuf.copy_user_buffer()) + } +} + +/// Usercall `write`. See the ABI documentation for more information. +#[unstable(feature = "sgx_platform", issue = "56975")] pub fn write(fd: Fd, buf: &[u8]) -> IoResult<usize> { unsafe { let userbuf = alloc::User::new_from_enclave(buf); @@ -40,19 +47,25 @@ pub fn write(fd: Fd, buf: &[u8]) -> IoResult<usize> { } } +/// Usercall `flush`. See the ABI documentation for more information. +#[unstable(feature = "sgx_platform", issue = "56975")] pub fn flush(fd: Fd) -> IoResult<()> { unsafe { raw::flush(fd).from_sgx_result() } } +/// Usercall `close`. See the ABI documentation for more information. +#[unstable(feature = "sgx_platform", issue = "56975")] pub fn close(fd: Fd) { unsafe { raw::close(fd) } } fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String { - String::from_utf8(copy_user_buffer(buf)) + String::from_utf8(buf.copy_user_buffer()) .unwrap_or_else(|_| panic!("Usercall {}: expected {} to be valid UTF-8", usercall, arg)) } +/// Usercall `bind_stream`. See the ABI documentation for more information. +#[unstable(feature = "sgx_platform", issue = "56975")] pub fn bind_stream(addr: &str) -> IoResult<(Fd, String)> { unsafe { let addr_user = alloc::User::new_from_enclave(addr.as_bytes()); @@ -67,6 +80,8 @@ pub fn bind_stream(addr: &str) -> IoResult<(Fd, String)> { } } +/// Usercall `accept_stream`. See the ABI documentation for more information. +#[unstable(feature = "sgx_platform", issue = "56975")] pub fn accept_stream(fd: Fd) -> IoResult<(Fd, String, String)> { unsafe { let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized(); @@ -84,6 +99,8 @@ pub fn accept_stream(fd: Fd) -> IoResult<(Fd, String, String)> { } } +/// Usercall `connect_stream`. See the ABI documentation for more information. +#[unstable(feature = "sgx_platform", issue = "56975")] pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> { unsafe { let addr_user = alloc::User::new_from_enclave(addr.as_bytes()); @@ -103,31 +120,45 @@ pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> { } } -pub fn launch_thread() -> IoResult<()> { - unsafe { raw::launch_thread().from_sgx_result() } +/// Usercall `launch_thread`. See the ABI documentation for more information. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub unsafe fn launch_thread() -> IoResult<()> { + raw::launch_thread().from_sgx_result() } +/// Usercall `exit`. See the ABI documentation for more information. +#[unstable(feature = "sgx_platform", issue = "56975")] pub fn exit(panic: bool) -> ! { unsafe { raw::exit(panic) } } +/// Usercall `wait`. See the ABI documentation for more information. +#[unstable(feature = "sgx_platform", issue = "56975")] pub fn wait(event_mask: u64, timeout: u64) -> IoResult<u64> { unsafe { raw::wait(event_mask, timeout).from_sgx_result() } } +/// Usercall `send`. See the ABI documentation for more information. +#[unstable(feature = "sgx_platform", issue = "56975")] pub fn send(event_set: u64, tcs: Option<Tcs>) -> IoResult<()> { unsafe { raw::send(event_set, tcs).from_sgx_result() } } +/// Usercall `insecure_time`. See the ABI documentation for more information. +#[unstable(feature = "sgx_platform", issue = "56975")] pub fn insecure_time() -> Duration { let t = unsafe { raw::insecure_time() }; Duration::new(t / 1_000_000_000, (t % 1_000_000_000) as _) } +/// Usercall `alloc`. See the ABI documentation for more information. +#[unstable(feature = "sgx_platform", issue = "56975")] pub fn alloc(size: usize, alignment: usize) -> IoResult<*mut u8> { unsafe { raw::alloc(size, alignment).from_sgx_result() } } +#[unstable(feature = "sgx_platform", issue = "56975")] +#[doc(inline)] pub use self::raw::free; fn check_os_error(err: Result) -> i32 { diff --git a/src/libstd/sys/sgx/abi/usercalls/raw.rs b/src/libstd/sys/sgx/abi/usercalls/raw.rs index a28d41c1b74..44b370c44c6 100644 --- a/src/libstd/sys/sgx/abi/usercalls/raw.rs +++ b/src/libstd/sys/sgx/abi/usercalls/raw.rs @@ -10,7 +10,8 @@ #![allow(unused)] -use fortanix_sgx_abi::*; +#[unstable(feature = "sgx_platform", issue = "56975")] +pub use fortanix_sgx_abi::*; use ptr::NonNull; @@ -21,7 +22,16 @@ extern "C" { fn usercall(nr: u64, p1: u64, p2: u64, _ignore: u64, p3: u64, p4: u64) -> UsercallReturn; } -unsafe fn do_usercall(nr: u64, p1: u64, p2: u64, p3: u64, p4: u64) -> (u64, u64) { +/// Perform the raw usercall operation as defined in the ABI calling convention. +/// +/// # Safety +/// The caller must ensure to pass parameters appropriate for the usercall `nr` +/// and to observe all requirements specified in the ABI. +/// +/// # Panics +/// Panics if `nr` is 0. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub unsafe fn do_usercall(nr: u64, p1: u64, p2: u64, p3: u64, p4: u64) -> (u64, u64) { if nr==0 { panic!("Invalid usercall number {}",nr) } let UsercallReturn(a, b) = usercall(nr,p1,p2,0,p3,p4); (a, b) @@ -169,6 +179,9 @@ impl<T: RegisterArgument, U: RegisterArgument> ReturnValue for (T, U) { macro_rules! enclave_usercalls_internal_define_usercalls { (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty, $n4:ident: $t4:ty) -> $r:ty) => ( + /// This is the raw function definition, see the ABI documentation for + /// more information. + #[unstable(feature = "sgx_platform", issue = "56975")] #[inline(always)] pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( @@ -181,6 +194,9 @@ macro_rules! enclave_usercalls_internal_define_usercalls { } ); (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:ty) => ( + /// This is the raw function definition, see the ABI documentation for + /// more information. + #[unstable(feature = "sgx_platform", issue = "56975")] #[inline(always)] pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( @@ -193,6 +209,9 @@ macro_rules! enclave_usercalls_internal_define_usercalls { } ); (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:ty) => ( + /// This is the raw function definition, see the ABI documentation for + /// more information. + #[unstable(feature = "sgx_platform", issue = "56975")] #[inline(always)] pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( @@ -204,6 +223,9 @@ macro_rules! enclave_usercalls_internal_define_usercalls { } ); (def fn $f:ident($n1:ident: $t1:ty) -> $r:ty) => ( + /// This is the raw function definition, see the ABI documentation for + /// more information. + #[unstable(feature = "sgx_platform", issue = "56975")] #[inline(always)] pub unsafe fn $f($n1: $t1) -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( @@ -214,6 +236,9 @@ macro_rules! enclave_usercalls_internal_define_usercalls { } ); (def fn $f:ident() -> $r:ty) => ( + /// This is the raw function definition, see the ABI documentation for + /// more information. + #[unstable(feature = "sgx_platform", issue = "56975")] #[inline(always)] pub unsafe fn $f() -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( diff --git a/src/libstd/sys/sgx/args.rs b/src/libstd/sys/sgx/args.rs index 8fb35d7ef98..50627b8c913 100644 --- a/src/libstd/sys/sgx/args.rs +++ b/src/libstd/sys/sgx/args.rs @@ -9,7 +9,7 @@ // except according to those terms. use ffi::OsString; -use super::abi::usercalls::{copy_user_buffer, alloc, ByteBuffer}; +use super::abi::usercalls::{alloc, raw::ByteBuffer}; use sync::atomic::{AtomicUsize, Ordering}; use sys::os_str::Buf; use sys_common::FromInner; @@ -22,7 +22,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { if argc != 0 { let args = alloc::User::<[ByteBuffer]>::from_raw_parts(argv as _, argc as _); let args = args.iter() - .map( |a| OsString::from_inner(Buf { inner: copy_user_buffer(a) }) ) + .map( |a| OsString::from_inner(Buf { inner: a.copy_user_buffer() }) ) .collect::<ArgsStore>(); ARGS.store(Box::into_raw(Box::new(args)) as _, Ordering::Relaxed); } diff --git a/src/libstd/sys/sgx/net.rs b/src/libstd/sys/sgx/net.rs index 176d230846d..9cfe821fe51 100644 --- a/src/libstd/sys/sgx/net.rs +++ b/src/libstd/sys/sgx/net.rs @@ -29,7 +29,7 @@ struct Socket { } impl Socket { - fn new(fd: usercalls::Fd, local_addr: String) -> Socket { + fn new(fd: usercalls::raw::Fd, local_addr: String) -> Socket { Socket { inner: Arc::new(FileDesc::new(fd)), local_addr } } } diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs index a1551dbb53b..d1af98bd4f5 100644 --- a/src/libstd/sys/sgx/rwlock.rs +++ b/src/libstd/sys/sgx/rwlock.rs @@ -9,14 +9,25 @@ // except according to those terms. use num::NonZeroUsize; +use slice; +use str; -use super::waitqueue::{WaitVariable, WaitQueue, SpinMutex, NotifiedTcs, try_lock_or_false}; +use super::waitqueue::{ + try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable, +}; +use mem; pub struct RWLock { readers: SpinMutex<WaitVariable<Option<NonZeroUsize>>>, writer: SpinMutex<WaitVariable<bool>>, } +// Below is to check at compile time, that RWLock has size of 128 bytes. +#[allow(dead_code)] +unsafe fn rw_lock_size_assert(r: RWLock) { + mem::transmute::<RWLock, [u8; 128]>(r); +} + //unsafe impl Send for RWLock {} //unsafe impl Sync for RWLock {} // FIXME @@ -24,7 +35,7 @@ impl RWLock { pub const fn new() -> RWLock { RWLock { readers: SpinMutex::new(WaitVariable::new(None)), - writer: SpinMutex::new(WaitVariable::new(false)) + writer: SpinMutex::new(WaitVariable::new(false)), } } @@ -89,9 +100,11 @@ impl RWLock { } #[inline] - pub unsafe fn read_unlock(&self) { - let mut rguard = self.readers.lock(); - let wguard = self.writer.lock(); + unsafe fn __read_unlock( + &self, + mut rguard: SpinMutexGuard<WaitVariable<Option<NonZeroUsize>>>, + wguard: SpinMutexGuard<WaitVariable<bool>>, + ) { *rguard.lock_var_mut() = NonZeroUsize::new(rguard.lock_var().unwrap().get() - 1); if rguard.lock_var().is_some() { // There are other active readers @@ -107,9 +120,18 @@ impl RWLock { } #[inline] - pub unsafe fn write_unlock(&self) { + pub unsafe fn read_unlock(&self) { let rguard = self.readers.lock(); let wguard = self.writer.lock(); + self.__read_unlock(rguard, wguard); + } + + #[inline] + unsafe fn __write_unlock( + &self, + rguard: SpinMutexGuard<WaitVariable<Option<NonZeroUsize>>>, + wguard: SpinMutexGuard<WaitVariable<bool>>, + ) { if let Err(mut wguard) = WaitQueue::notify_one(wguard) { // No writers waiting, release the write lock *wguard.lock_var_mut() = false; @@ -129,5 +151,108 @@ impl RWLock { } #[inline] + pub unsafe fn write_unlock(&self) { + let rguard = self.readers.lock(); + let wguard = self.writer.lock(); + self.__write_unlock(rguard, wguard); + } + + #[inline] + unsafe fn unlock(&self) { + let rguard = self.readers.lock(); + let wguard = self.writer.lock(); + if *wguard.lock_var() == true { + self.__write_unlock(rguard, wguard); + } else { + self.__read_unlock(rguard, wguard); + } + } + + #[inline] pub unsafe fn destroy(&self) {} } + +const EINVAL: i32 = 22; + +#[no_mangle] +pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 { + if p.is_null() { + return EINVAL; + } + (*p).read(); + return 0; +} + +#[no_mangle] +pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RWLock) -> i32 { + if p.is_null() { + return EINVAL; + } + (*p).write(); + return 0; +} +#[no_mangle] +pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 { + if p.is_null() { + return EINVAL; + } + (*p).unlock(); + return 0; +} + +#[no_mangle] +pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { + if s < 0 { + return; + } + let buf = slice::from_raw_parts(m as *const u8, s as _); + if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { + eprint!("{}", s); + } +} + +#[no_mangle] +pub unsafe extern "C" fn __rust_abort() { + ::sys::abort_internal(); +} + +#[cfg(test)] +mod tests { + + use super::*; + use core::array::FixedSizeArray; + use mem::MaybeUninit; + use {mem, ptr}; + + // The below test verifies that the bytes of initialized RWLock are the ones + // we use in libunwind. + // If they change we need to update src/UnwindRustSgx.h in libunwind. + #[test] + fn test_c_rwlock_initializer() { + const RWLOCK_INIT: &[u8] = &[ + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ]; + + let mut init = MaybeUninit::<RWLock>::zeroed(); + init.set(RWLock::new()); + assert_eq!( + mem::transmute::<_, [u8; 128]>(init.into_inner()).as_slice(), + RWLOCK_INIT + ); + } +} diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs index 9de12a5e6f1..b8d5b17d8d2 100644 --- a/src/libstd/sys/sgx/thread.rs +++ b/src/libstd/sys/sgx/thread.rs @@ -75,7 +75,7 @@ impl Thread { pub fn yield_now() { assert_eq!( - usercalls::wait(0, usercalls::WAIT_NO).unwrap_err().kind(), + usercalls::wait(0, usercalls::raw::WAIT_NO).unwrap_err().kind(), io::ErrorKind::WouldBlock ); } @@ -97,5 +97,4 @@ pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option<Guard> { None } pub unsafe fn init() -> Option<Guard> { None } - pub unsafe fn deinit() {} } diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index d922be520d4..f30817e69ab 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -203,18 +203,21 @@ impl Socket { // Linux. This was added in 2.6.28, however, and because we support // 2.6.18 we must detect this support dynamically. if cfg!(target_os = "linux") { - weak! { - fn accept4(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int + syscall! { + fn accept4( + fd: c_int, + addr: *mut sockaddr, + addr_len: *mut socklen_t, + flags: c_int + ) -> c_int } - if let Some(accept) = accept4.get() { - let res = cvt_r(|| unsafe { - accept(self.0.raw(), storage, len, SOCK_CLOEXEC) - }); - match res { - Ok(fd) => return Ok(Socket(FileDesc::new(fd))), - Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} - Err(e) => return Err(e), - } + let res = cvt_r(|| unsafe { + accept4(self.0.raw(), storage, len, SOCK_CLOEXEC) + }); + match res { + Ok(fd) => return Ok(Socket(FileDesc::new(fd))), + Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {} + Err(e) => return Err(e), } } diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 03e81a720dc..6e8ee445994 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -67,7 +67,8 @@ pub fn errno() -> i32 { } /// Sets the platform-specific value of errno -#[cfg(any(target_os = "solaris", target_os = "fuchsia"))] // only needed for readdir so far +#[cfg(all(not(target_os = "linux"), + not(target_os = "dragonfly")))] // needed for readdir and syscall! pub fn set_errno(e: i32) { unsafe { *errno_location() = e as c_int @@ -84,6 +85,18 @@ pub fn errno() -> i32 { unsafe { errno as i32 } } +#[cfg(target_os = "dragonfly")] +pub fn set_errno(e: i32) { + extern { + #[thread_local] + static mut errno: c_int; + } + + unsafe { + errno = e; + } +} + /// Gets a detailed string description for the given error number. pub fn error_string(errno: i32) -> String { extern { diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 0a5dccdddda..24b2959a3fa 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -22,7 +22,7 @@ use sys::{cvt, cvt_r}; pub struct AnonPipe(FileDesc); pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - weak! { fn pipe2(*mut c_int, c_int) -> c_int } + syscall! { fn pipe2(fds: *mut c_int, flags: c_int) -> c_int } static INVALID: AtomicBool = ATOMIC_BOOL_INIT; let mut fds = [0; 2]; @@ -39,22 +39,20 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { !INVALID.load(Ordering::SeqCst) { - if let Some(pipe) = pipe2.get() { - // Note that despite calling a glibc function here we may still - // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to - // emulate on older kernels, so if you happen to be running on - // an older kernel you may see `pipe2` as a symbol but still not - // see the syscall. - match cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) { - Ok(_) => { - return Ok((AnonPipe(FileDesc::new(fds[0])), - AnonPipe(FileDesc::new(fds[1])))); - } - Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => { - INVALID.store(true, Ordering::SeqCst); - } - Err(e) => return Err(e), + // Note that despite calling a glibc function here we may still + // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to + // emulate on older kernels, so if you happen to be running on + // an older kernel you may see `pipe2` as a symbol but still not + // see the syscall. + match cvt(unsafe { pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) }) { + Ok(_) => { + return Ok((AnonPipe(FileDesc::new(fds[0])), + AnonPipe(FileDesc::new(fds[1])))); + } + Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => { + INVALID.store(true, Ordering::SeqCst); } + Err(e) => return Err(e), } } cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 4ff060018ae..e0d2c620498 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -211,7 +211,6 @@ pub mod guard { pub type Guard = Range<usize>; pub unsafe fn current() -> Option<Guard> { None } pub unsafe fn init() -> Option<Guard> { None } - pub unsafe fn deinit() {} } @@ -355,26 +354,6 @@ pub mod guard { } } - pub unsafe fn deinit() { - if !cfg!(target_os = "linux") { - if let Some(stackaddr) = get_stack_start_aligned() { - // Remove the protection on the guard page. - // FIXME: we cannot unmap the page, because when we mmap() - // above it may be already mapped by the OS, which we can't - // detect from mmap()'s return value. If we unmap this page, - // it will lead to failure growing stack size on platforms like - // macOS. Instead, just restore the page to a writable state. - // This ain't Linux, so we probably don't need to care about - // execstack. - let result = mprotect(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE); - - if result != 0 { - panic!("unable to reset the guard page"); - } - } - } - } - #[cfg(any(target_os = "macos", target_os = "bitrig", target_os = "openbsd", diff --git a/src/libstd/sys/unix/weak.rs b/src/libstd/sys/unix/weak.rs index 18944be58ee..7d293f1c47a 100644 --- a/src/libstd/sys/unix/weak.rs +++ b/src/libstd/sys/unix/weak.rs @@ -77,3 +77,38 @@ unsafe fn fetch(name: &str) -> usize { }; libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize } + +#[cfg(not(target_os = "linux"))] +macro_rules! syscall { + (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + unsafe fn $name($($arg_name: $t),*) -> $ret { + use libc; + use super::os; + + weak! { fn $name($($t),*) -> $ret } + + if let Some(fun) = $name.get() { + fun($($arg_name),*) + } else { + os::set_errno(libc::ENOSYS); + -1 + } + } + ) +} + +#[cfg(target_os = "linux")] +macro_rules! syscall { + (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + unsafe fn $name($($arg_name:$t),*) -> $ret { + // This looks like a hack, but concat_idents only accepts idents + // (not paths). + use libc::*; + + syscall( + concat_idents!(SYS_, $name), + $($arg_name as c_long),* + ) as $ret + } + ) +} diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs index 3d74ffdc14a..f9abb0b825a 100644 --- a/src/libstd/sys/wasm/thread.rs +++ b/src/libstd/sys/wasm/thread.rs @@ -68,7 +68,6 @@ pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option<Guard> { None } pub unsafe fn init() -> Option<Guard> { None } - pub unsafe fn deinit() {} } cfg_if! { diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 1a97dd10ced..621ae2fda58 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -98,5 +98,4 @@ pub mod guard { pub type Guard = !; pub unsafe fn current() -> Option<Guard> { None } pub unsafe fn init() -> Option<Guard> { None } - pub unsafe fn deinit() {} } diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 77371782977..e44113f76f4 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -14,11 +14,12 @@ use env; use io::prelude::*; use io; +use path::{self, Path}; +use ptr; +use rustc_demangle::demangle; use str; use sync::atomic::{self, Ordering}; -use path::{self, Path}; use sys::mutex::Mutex; -use ptr; pub use sys::backtrace::{ unwind_backtrace, @@ -191,7 +192,14 @@ fn output(w: &mut dyn Write, idx: usize, frame: Frame, PrintFormat::Short => write!(w, " {:2}: ", idx)?, } match s { - Some(string) => demangle(w, string, format)?, + Some(string) => { + let symbol = demangle(string); + match format { + PrintFormat::Full => write!(w, "{}", symbol)?, + // strip the trailing hash if short mode + PrintFormat::Short => write!(w, "{:#}", symbol)?, + } + } None => w.write_all(b"<unknown>")?, } w.write_all(b"\n") @@ -235,228 +243,3 @@ fn output_fileline(w: &mut dyn Write, w.write_all(b"\n") } - -// All rust symbols are in theory lists of "::"-separated identifiers. Some -// assemblers, however, can't handle these characters in symbol names. To get -// around this, we use C++-style mangling. The mangling method is: -// -// 1. Prefix the symbol with "_ZN" -// 2. For each element of the path, emit the length plus the element -// 3. End the path with "E" -// -// For example, "_ZN4testE" => "test" and "_ZN3foo3barE" => "foo::bar". -// -// We're the ones printing our backtraces, so we can't rely on anything else to -// demangle our symbols. It's *much* nicer to look at demangled symbols, so -// this function is implemented to give us nice pretty output. -// -// Note that this demangler isn't quite as fancy as it could be. We have lots -// of other information in our symbols like hashes, version, type information, -// etc. Additionally, this doesn't handle glue symbols at all. -pub fn demangle(writer: &mut dyn Write, mut s: &str, format: PrintFormat) -> io::Result<()> { - // During ThinLTO LLVM may import and rename internal symbols, so strip out - // those endings first as they're one of the last manglings applied to - // symbol names. - let llvm = ".llvm."; - if let Some(i) = s.find(llvm) { - let candidate = &s[i + llvm.len()..]; - let all_hex = candidate.chars().all(|c| { - match c { - 'A' ..= 'F' | '0' ..= '9' => true, - _ => false, - } - }); - - if all_hex { - s = &s[..i]; - } - } - - // Validate the symbol. If it doesn't look like anything we're - // expecting, we just print it literally. Note that we must handle non-rust - // symbols because we could have any function in the backtrace. - let mut valid = true; - let mut inner = s; - if s.len() > 4 && s.starts_with("_ZN") && s.ends_with("E") { - inner = &s[3 .. s.len() - 1]; - // On Windows, dbghelp strips leading underscores, so we accept "ZN...E" form too. - } else if s.len() > 3 && s.starts_with("ZN") && s.ends_with("E") { - inner = &s[2 .. s.len() - 1]; - } else { - valid = false; - } - - if valid { - let mut chars = inner.chars(); - while valid { - let mut i = 0; - for c in chars.by_ref() { - if c.is_numeric() { - i = i * 10 + c as usize - '0' as usize; - } else { - break - } - } - if i == 0 { - valid = chars.next().is_none(); - break - } else if chars.by_ref().take(i - 1).count() != i - 1 { - valid = false; - } - } - } - - // Alright, let's do this. - if !valid { - writer.write_all(s.as_bytes())?; - } else { - // remove the `::hfc2edb670e5eda97` part at the end of the symbol. - if format == PrintFormat::Short { - // The symbol in still mangled. - let mut split = inner.rsplitn(2, "17h"); - match (split.next(), split.next()) { - (Some(addr), rest) => { - if addr.len() == 16 && - addr.chars().all(|c| c.is_digit(16)) - { - inner = rest.unwrap_or(""); - } - } - _ => (), - } - } - - let mut first = true; - while !inner.is_empty() { - if !first { - writer.write_all(b"::")?; - } else { - first = false; - } - let mut rest = inner; - while rest.chars().next().unwrap().is_numeric() { - rest = &rest[1..]; - } - let i: usize = inner[.. (inner.len() - rest.len())].parse().unwrap(); - inner = &rest[i..]; - rest = &rest[..i]; - if rest.starts_with("_$") { - rest = &rest[1..]; - } - while !rest.is_empty() { - if rest.starts_with(".") { - if let Some('.') = rest[1..].chars().next() { - writer.write_all(b"::")?; - rest = &rest[2..]; - } else { - writer.write_all(b".")?; - rest = &rest[1..]; - } - } else if rest.starts_with("$") { - macro_rules! demangle { - ($($pat:expr => $demangled:expr),*) => ({ - $(if rest.starts_with($pat) { - writer.write_all($demangled)?; - rest = &rest[$pat.len()..]; - } else)* - { - writer.write_all(rest.as_bytes())?; - break; - } - - }) - } - - // see src/librustc/back/link.rs for these mappings - demangle! ( - "$SP$" => b"@", - "$BP$" => b"*", - "$RF$" => b"&", - "$LT$" => b"<", - "$GT$" => b">", - "$LP$" => b"(", - "$RP$" => b")", - "$C$" => b",", - - // in theory we can demangle any Unicode code point, but - // for simplicity we just catch the common ones. - "$u7e$" => b"~", - "$u20$" => b" ", - "$u27$" => b"'", - "$u5b$" => b"[", - "$u5d$" => b"]", - "$u7b$" => b"{", - "$u7d$" => b"}", - "$u3b$" => b";", - "$u2b$" => b"+", - "$u22$" => b"\"" - ) - } else { - let idx = match rest.char_indices().find(|&(_, c)| c == '$' || c == '.') { - None => rest.len(), - Some((i, _)) => i, - }; - writer.write_all(rest[..idx].as_bytes())?; - rest = &rest[idx..]; - } - } - } - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - use sys_common; - macro_rules! t { ($a:expr, $b:expr) => ({ - let mut m = Vec::new(); - sys_common::backtrace::demangle(&mut m, - $a, - super::PrintFormat::Full).unwrap(); - assert_eq!(String::from_utf8(m).unwrap(), $b); - }) } - - #[test] - fn demangle() { - t!("test", "test"); - t!("_ZN4testE", "test"); - t!("_ZN4test", "_ZN4test"); - t!("_ZN4test1a2bcE", "test::a::bc"); - } - - #[test] - fn demangle_dollars() { - t!("_ZN4$RP$E", ")"); - t!("_ZN8$RF$testE", "&test"); - t!("_ZN8$BP$test4foobE", "*test::foob"); - t!("_ZN9$u20$test4foobE", " test::foob"); - t!("_ZN35Bar$LT$$u5b$u32$u3b$$u20$4$u5d$$GT$E", "Bar<[u32; 4]>"); - } - - #[test] - fn demangle_many_dollars() { - t!("_ZN13test$u20$test4foobE", "test test::foob"); - t!("_ZN12test$BP$test4foobE", "test*test::foob"); - } - - #[test] - fn demangle_windows() { - t!("ZN4testE", "test"); - t!("ZN13test$u20$test4foobE", "test test::foob"); - t!("ZN12test$RF$test4foobE", "test&test::foob"); - } - - #[test] - fn demangle_elements_beginning_with_underscore() { - t!("_ZN13_$LT$test$GT$E", "<test>"); - t!("_ZN28_$u7b$$u7b$closure$u7d$$u7d$E", "{{closure}}"); - t!("_ZN15__STATIC_FMTSTRE", "__STATIC_FMTSTR"); - } - - #[test] - fn demangle_trait_impls() { - t!("_ZN71_$LT$Test$u20$$u2b$$u20$$u27$static$u20$as$u20$foo..Bar$LT$Test$GT$$GT$3barE", - "<Test + 'static as foo::Bar<Test>>::bar"); - } -} |
