about summary refs log tree commit diff
path: root/library/std
diff options
context:
space:
mode:
Diffstat (limited to 'library/std')
-rw-r--r--library/std/Cargo.toml4
-rw-r--r--library/std/build.rs71
-rw-r--r--library/std/src/error.rs4
-rw-r--r--library/std/src/fs/tests.rs3
-rw-r--r--library/std/src/io/impls.rs14
-rw-r--r--library/std/src/io/mod.rs12
-rw-r--r--library/std/src/io/stdio.rs177
-rw-r--r--library/std/src/lib.rs5
-rw-r--r--library/std/src/panicking.rs12
-rw-r--r--library/std/src/sys/cloudabi/mod.rs5
-rw-r--r--library/std/src/sys/sgx/abi/mem.rs12
-rw-r--r--library/std/src/sys/sgx/alloc.rs46
-rw-r--r--library/std/src/sys/unix/kernel_copy.rs18
-rw-r--r--library/std/src/sys/unix/mod.rs52
-rw-r--r--library/std/src/sys/unix/rand.rs15
-rw-r--r--library/std/src/sys/unix/weak.rs66
-rw-r--r--library/std/src/sys/wasm/alloc.rs2
-rw-r--r--library/std/src/sys/windows/mod.rs14
-rw-r--r--library/std/src/thread/mod.rs6
-rw-r--r--library/std/tests/run-time-detect.rs70
20 files changed, 331 insertions, 277 deletions
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 281ed4f336c..ad9d1238370 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -36,7 +36,7 @@ features = ['read_core', 'elf', 'macho', 'pe']
 rand = "0.7"
 
 [target.'cfg(any(all(target_arch = "wasm32", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
-dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
+dlmalloc = { version = "0.2.1", features = ['rustc-dep-of-std'] }
 
 [target.x86_64-fortanix-unknown-sgx.dependencies]
 fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
@@ -60,6 +60,8 @@ panic-unwind = ["panic_unwind"]
 profiler = ["profiler_builtins"]
 compiler-builtins-c = ["alloc/compiler-builtins-c"]
 compiler-builtins-mem = ["alloc/compiler-builtins-mem"]
+compiler-builtins-asm = ["alloc/compiler-builtins-asm"]
+compiler-builtins-mangled-names = ["alloc/compiler-builtins-mangled-names"]
 llvm-libunwind = ["unwind/llvm-libunwind"]
 system-llvm-libunwind = ["unwind/system-llvm-libunwind"]
 
diff --git a/library/std/build.rs b/library/std/build.rs
index f2ed7552afb..f730569f74b 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -3,66 +3,23 @@ use std::env;
 fn main() {
     println!("cargo:rerun-if-changed=build.rs");
     let target = env::var("TARGET").expect("TARGET was not set");
-    if target.contains("linux") {
-        if target.contains("android") {
-            println!("cargo:rustc-link-lib=dl");
-            println!("cargo:rustc-link-lib=log");
-            println!("cargo:rustc-link-lib=gcc");
-        }
-    } else if target.contains("freebsd") {
-        println!("cargo:rustc-link-lib=execinfo");
-        println!("cargo:rustc-link-lib=pthread");
+    if target.contains("freebsd") {
         if env::var("RUST_STD_FREEBSD_12_ABI").is_ok() {
             println!("cargo:rustc-cfg=freebsd12");
         }
-    } else if target.contains("netbsd") {
-        println!("cargo:rustc-link-lib=pthread");
-        println!("cargo:rustc-link-lib=rt");
-    } else if target.contains("dragonfly") || target.contains("openbsd") {
-        println!("cargo:rustc-link-lib=pthread");
-    } else if target.contains("solaris") {
-        println!("cargo:rustc-link-lib=socket");
-        println!("cargo:rustc-link-lib=posix4");
-        println!("cargo:rustc-link-lib=pthread");
-        println!("cargo:rustc-link-lib=resolv");
-    } else if target.contains("illumos") {
-        println!("cargo:rustc-link-lib=socket");
-        println!("cargo:rustc-link-lib=posix4");
-        println!("cargo:rustc-link-lib=pthread");
-        println!("cargo:rustc-link-lib=resolv");
-        println!("cargo:rustc-link-lib=nsl");
-        // Use libumem for the (malloc-compatible) allocator
-        println!("cargo:rustc-link-lib=umem");
-    } else if target.contains("apple-darwin") {
-        println!("cargo:rustc-link-lib=System");
-
-        // res_init and friends require -lresolv on macOS/iOS.
-        // See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
-        println!("cargo:rustc-link-lib=resolv");
-    } else if target.contains("apple-ios") {
-        println!("cargo:rustc-link-lib=System");
-        println!("cargo:rustc-link-lib=objc");
-        println!("cargo:rustc-link-lib=framework=Security");
-        println!("cargo:rustc-link-lib=framework=Foundation");
-        println!("cargo:rustc-link-lib=resolv");
-    } else if target.contains("uwp") {
-        println!("cargo:rustc-link-lib=ws2_32");
-        // For BCryptGenRandom
-        println!("cargo:rustc-link-lib=bcrypt");
-    } else if target.contains("windows") {
-        println!("cargo:rustc-link-lib=advapi32");
-        println!("cargo:rustc-link-lib=ws2_32");
-        println!("cargo:rustc-link-lib=userenv");
-    } else if target.contains("fuchsia") {
-        println!("cargo:rustc-link-lib=zircon");
-        println!("cargo:rustc-link-lib=fdio");
-    } else if target.contains("cloudabi") {
-        if cfg!(feature = "backtrace") {
-            println!("cargo:rustc-link-lib=unwind");
-        }
-        println!("cargo:rustc-link-lib=c");
-        println!("cargo:rustc-link-lib=compiler_rt");
-    } else if (target.contains("sgx") && target.contains("fortanix"))
+    } else if target.contains("linux")
+        || target.contains("netbsd")
+        || target.contains("dragonfly")
+        || target.contains("openbsd")
+        || target.contains("solaris")
+        || target.contains("illumos")
+        || target.contains("apple-darwin")
+        || target.contains("apple-ios")
+        || target.contains("uwp")
+        || target.contains("windows")
+        || target.contains("fuchsia")
+        || target.contains("cloudabi")
+        || (target.contains("sgx") && target.contains("fortanix"))
         || target.contains("hermit")
         || target.contains("l4re")
         || target.contains("redox")
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index 5771ca758af..0044e59d697 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -19,7 +19,7 @@ mod tests;
 use core::array;
 use core::convert::Infallible;
 
-use crate::alloc::{AllocError, LayoutErr};
+use crate::alloc::{AllocError, LayoutError};
 use crate::any::TypeId;
 use crate::backtrace::Backtrace;
 use crate::borrow::Cow;
@@ -390,7 +390,7 @@ impl Error for ! {}
 impl Error for AllocError {}
 
 #[stable(feature = "alloc_layout", since = "1.28.0")]
-impl Error for LayoutErr {}
+impl Error for LayoutError {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Error for str::ParseBoolError {
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 0642dca8e48..5c969741592 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1341,6 +1341,9 @@ fn metadata_access_times() {
 #[test]
 fn symlink_hard_link() {
     let tmpdir = tmpdir();
+    if !got_symlink_permission(&tmpdir) {
+        return;
+    };
 
     // Create "file", a file.
     check!(fs::File::create(tmpdir.join("file")));
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index 66426101d27..6b3c86cb0df 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -209,20 +209,6 @@ impl<B: BufRead + ?Sized> BufRead for Box<B> {
     }
 }
 
-// Used by panicking::default_hook
-#[cfg(test)]
-/// This impl is only used by printing logic, so any error returned is always
-/// of kind `Other`, and should be ignored.
-impl Write for dyn ::realstd::io::LocalOutput {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        (*self).write(buf).map_err(|_| ErrorKind::Other.into())
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        (*self).flush().map_err(|_| ErrorKind::Other.into())
-    }
-}
-
 // =============================================================================
 // In-memory buffer implementations
 
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 57413f9bc40..dfbf6c3f244 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -271,20 +271,18 @@ pub use self::copy::copy;
 pub use self::cursor::Cursor;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::error::{Error, ErrorKind, Result};
+#[unstable(feature = "internal_output_capture", issue = "none")]
+#[doc(no_inline, hidden)]
+pub use self::stdio::set_output_capture;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::stdio::{StderrLock, StdinLock, StdoutLock};
 #[unstable(feature = "print_internals", issue = "none")]
 pub use self::stdio::{_eprint, _print};
-#[unstable(feature = "libstd_io_internals", issue = "42788")]
-#[doc(no_inline, hidden)]
-pub use self::stdio::{set_panic, set_print, LocalOutput};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::util::{empty, repeat, sink, Empty, Repeat, Sink};
 
-pub(crate) use self::stdio::clone_io;
-
 mod buffered;
 pub(crate) mod copy;
 mod cursor;
@@ -1309,10 +1307,10 @@ pub trait Write {
         default_write_vectored(|b| self.write(b), bufs)
     }
 
-    /// Determines if this `Write`er has an efficient [`write_vectored`]
+    /// Determines if this `Write`r has an efficient [`write_vectored`]
     /// implementation.
     ///
-    /// If a `Write`er does not override the default [`write_vectored`]
+    /// If a `Write`r does not override the default [`write_vectored`]
     /// implementation, code using it may want to avoid the method all together
     /// and coalesce writes into a single buffer for higher performance.
     ///
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 8fbce09dd63..6ea7704d422 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -5,44 +5,38 @@ mod tests;
 
 use crate::io::prelude::*;
 
-use crate::cell::RefCell;
+use crate::cell::{Cell, RefCell};
 use crate::fmt;
 use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter};
 use crate::lazy::SyncOnceCell;
 use crate::sync::atomic::{AtomicBool, Ordering};
-use crate::sync::{Mutex, MutexGuard};
+use crate::sync::{Arc, Mutex, MutexGuard};
 use crate::sys::stdio;
 use crate::sys_common;
 use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
-use crate::thread::LocalKey;
 
-thread_local! {
-    /// Used by the test crate to capture the output of the print! and println! macros.
-    static LOCAL_STDOUT: RefCell<Option<Box<dyn LocalOutput>>> = {
-        RefCell::new(None)
-    }
-}
+type LocalStream = Arc<Mutex<Vec<u8>>>;
 
 thread_local! {
-    /// Used by the test crate to capture the output of the eprint! and eprintln! macros, and panics.
-    static LOCAL_STDERR: RefCell<Option<Box<dyn LocalOutput>>> = {
-        RefCell::new(None)
+    /// Used by the test crate to capture the output of the print macros and panics.
+    static OUTPUT_CAPTURE: Cell<Option<LocalStream>> = {
+        Cell::new(None)
     }
 }
 
-/// Flag to indicate LOCAL_STDOUT and/or LOCAL_STDERR is used.
+/// Flag to indicate OUTPUT_CAPTURE is used.
 ///
-/// If both are None and were never set on any thread, this flag is set to
-/// false, and both LOCAL_STDOUT and LOCAL_STDOUT can be safely ignored on all
-/// threads, saving some time and memory registering an unused thread local.
+/// If it is None and was never set on any thread, this flag is set to false,
+/// and OUTPUT_CAPTURE can be safely ignored on all threads, saving some time
+/// and memory registering an unused thread local.
 ///
-/// Note about memory ordering: This contains information about whether two
-/// thread local variables might be in use. Although this is a global flag, the
+/// Note about memory ordering: This contains information about whether a
+/// thread local variable might be in use. Although this is a global flag, the
 /// memory ordering between threads does not matter: we only want this flag to
-/// have a consistent order between set_print/set_panic and print_to *within
+/// have a consistent order between set_output_capture and print_to *within
 /// the same thread*. Within the same thread, things always have a perfectly
 /// consistent order. So Ordering::Relaxed is fine.
-static LOCAL_STREAMS: AtomicBool = AtomicBool::new(false);
+static OUTPUT_CAPTURE_USED: AtomicBool = AtomicBool::new(false);
 
 /// A handle to a raw instance of the standard input stream of this process.
 ///
@@ -896,97 +890,24 @@ impl fmt::Debug for StderrLock<'_> {
     }
 }
 
-/// A writer than can be cloned to new threads.
-#[unstable(
-    feature = "set_stdio",
-    reason = "this trait may disappear completely or be replaced \
-                     with a more general mechanism",
-    issue = "none"
-)]
-#[doc(hidden)]
-pub trait LocalOutput: Write + Send {
-    fn clone_box(&self) -> Box<dyn LocalOutput>;
-}
-
-/// Resets the thread-local stderr handle to the specified writer
-///
-/// This will replace the current thread's stderr handle, returning the old
-/// handle. All future calls to `panic!` and friends will emit their output to
-/// this specified handle.
-///
-/// Note that this does not need to be called for all new threads; the default
-/// output handle is to the process's stderr stream.
-#[unstable(
-    feature = "set_stdio",
-    reason = "this function may disappear completely or be replaced \
-                     with a more general mechanism",
-    issue = "none"
-)]
-#[doc(hidden)]
-pub fn set_panic(sink: Option<Box<dyn LocalOutput>>) -> Option<Box<dyn LocalOutput>> {
-    use crate::mem;
-    if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
-        // LOCAL_STDERR is definitely None since LOCAL_STREAMS is false.
-        return None;
-    }
-    let s = LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(
-        |mut s| {
-            let _ = s.flush();
-            Some(s)
-        },
-    );
-    LOCAL_STREAMS.store(true, Ordering::Relaxed);
-    s
-}
-
-/// Resets the thread-local stdout handle to the specified writer
-///
-/// This will replace the current thread's stdout handle, returning the old
-/// handle. All future calls to `print!` and friends will emit their output to
-/// this specified handle.
-///
-/// Note that this does not need to be called for all new threads; the default
-/// output handle is to the process's stdout stream.
+/// Sets the thread-local output capture buffer and returns the old one.
 #[unstable(
-    feature = "set_stdio",
-    reason = "this function may disappear completely or be replaced \
-                     with a more general mechanism",
+    feature = "internal_output_capture",
+    reason = "this function is meant for use in the test crate \
+        and may disappear in the future",
     issue = "none"
 )]
 #[doc(hidden)]
-pub fn set_print(sink: Option<Box<dyn LocalOutput>>) -> Option<Box<dyn LocalOutput>> {
-    use crate::mem;
-    if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
-        // LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false.
+pub fn set_output_capture(sink: Option<LocalStream>) -> Option<LocalStream> {
+    if sink.is_none() && !OUTPUT_CAPTURE_USED.load(Ordering::Relaxed) {
+        // OUTPUT_CAPTURE is definitely None since OUTPUT_CAPTURE_USED is false.
         return None;
     }
-    let s = LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(
-        |mut s| {
-            let _ = s.flush();
-            Some(s)
-        },
-    );
-    LOCAL_STREAMS.store(true, Ordering::Relaxed);
-    s
-}
-
-pub(crate) fn clone_io() -> (Option<Box<dyn LocalOutput>>, Option<Box<dyn LocalOutput>>) {
-    // Don't waste time when LOCAL_{STDOUT,STDERR} are definitely None.
-    if !LOCAL_STREAMS.load(Ordering::Relaxed) {
-        return (None, None);
-    }
-
-    LOCAL_STDOUT.with(|stdout| {
-        LOCAL_STDERR.with(|stderr| {
-            (
-                stdout.borrow().as_ref().map(|o| o.clone_box()),
-                stderr.borrow().as_ref().map(|o| o.clone_box()),
-            )
-        })
-    })
+    OUTPUT_CAPTURE_USED.store(true, Ordering::Relaxed);
+    OUTPUT_CAPTURE.with(move |slot| slot.replace(sink))
 }
 
-/// Write `args` to output stream `local_s` if possible, `global_s`
+/// Write `args` to the capture buffer if enabled and possible, or `global_s`
 /// otherwise. `label` identifies the stream in a panic message.
 ///
 /// This function is used to print error messages, so it takes extra
@@ -996,36 +917,26 @@ pub(crate) fn clone_io() -> (Option<Box<dyn LocalOutput>>, Option<Box<dyn LocalO
 /// thread, it will just fall back to the global stream.
 ///
 /// However, if the actual I/O causes an error, this function does panic.
-fn print_to<T>(
-    args: fmt::Arguments<'_>,
-    local_s: &'static LocalKey<RefCell<Option<Box<dyn LocalOutput>>>>,
-    global_s: fn() -> T,
-    label: &str,
-) where
+fn print_to<T>(args: fmt::Arguments<'_>, global_s: fn() -> T, label: &str)
+where
     T: Write,
 {
-    let result = LOCAL_STREAMS
-        .load(Ordering::Relaxed)
-        .then(|| {
-            local_s
-                .try_with(|s| {
-                    // Note that we completely remove a local sink to write to in case
-                    // our printing recursively panics/prints, so the recursive
-                    // panic/print goes to the global sink instead of our local sink.
-                    let prev = s.borrow_mut().take();
-                    if let Some(mut w) = prev {
-                        let result = w.write_fmt(args);
-                        *s.borrow_mut() = Some(w);
-                        return result;
-                    }
-                    global_s().write_fmt(args)
-                })
-                .ok()
-        })
-        .flatten()
-        .unwrap_or_else(|| global_s().write_fmt(args));
-
-    if let Err(e) = result {
+    if OUTPUT_CAPTURE_USED.load(Ordering::Relaxed)
+        && OUTPUT_CAPTURE.try_with(|s| {
+            // Note that we completely remove a local sink to write to in case
+            // our printing recursively panics/prints, so the recursive
+            // panic/print goes to the global sink instead of our local sink.
+            s.take().map(|w| {
+                let _ = w.lock().unwrap_or_else(|e| e.into_inner()).write_fmt(args);
+                s.set(Some(w));
+            })
+        }) == Ok(Some(()))
+    {
+        // Succesfully wrote to capture buffer.
+        return;
+    }
+
+    if let Err(e) = global_s().write_fmt(args) {
         panic!("failed printing to {}: {}", label, e);
     }
 }
@@ -1038,7 +949,7 @@ fn print_to<T>(
 #[doc(hidden)]
 #[cfg(not(test))]
 pub fn _print(args: fmt::Arguments<'_>) {
-    print_to(args, &LOCAL_STDOUT, stdout, "stdout");
+    print_to(args, stdout, "stdout");
 }
 
 #[unstable(
@@ -1049,7 +960,7 @@ pub fn _print(args: fmt::Arguments<'_>) {
 #[doc(hidden)]
 #[cfg(not(test))]
 pub fn _eprint(args: fmt::Arguments<'_>) {
-    print_to(args, &LOCAL_STDERR, stderr, "stderr");
+    print_to(args, stderr, "stderr");
 }
 
 #[cfg(test)]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index ffc9cf3f2eb..db523f05e01 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -207,7 +207,7 @@
 // std may use features in a platform-specific way
 #![allow(unused_features)]
 #![cfg_attr(not(bootstrap), feature(rustc_allow_const_fn_unstable))]
-#![cfg_attr(test, feature(print_internals, set_stdio, update_panic_count))]
+#![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))]
 #![cfg_attr(
     all(target_vendor = "fortanix", target_env = "sgx"),
     feature(slice_index_methods, coerce_unsized, sgx_platform)
@@ -298,6 +298,7 @@
 #![feature(raw)]
 #![feature(raw_ref_macros)]
 #![feature(ready_macro)]
+#![feature(refcell_take)]
 #![feature(rustc_attrs)]
 #![feature(rustc_private)]
 #![feature(shrink_to)]
@@ -565,5 +566,5 @@ include!("keyword_docs.rs");
 // This is required to avoid an unstable error when `restricted-std` is not
 // enabled. The use of #![feature(restricted_std)] in rustc-std-workspace-std
 // is unconditional, so the unstable feature needs to be defined somewhere.
-#[cfg_attr(not(feature = "restricted-std"), unstable(feature = "restricted_std", issue = "none"))]
+#[unstable(feature = "restricted_std", issue = "none")]
 mod __restricted_std_workaround {}
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index fbbc61f4e60..8ba3feccb6b 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -24,11 +24,11 @@ use crate::sys_common::{thread_info, util};
 use crate::thread;
 
 #[cfg(not(test))]
-use crate::io::set_panic;
+use crate::io::set_output_capture;
 // make sure to use the stderr output configured
 // by libtest in the real copy of std
 #[cfg(test)]
-use realstd::io::set_panic;
+use realstd::io::set_output_capture;
 
 // Binary interface to the panic runtime that the standard library depends on.
 //
@@ -218,11 +218,9 @@ fn default_hook(info: &PanicInfo<'_>) {
         }
     };
 
-    if let Some(mut local) = set_panic(None) {
-        // NB. In `cfg(test)` this uses the forwarding impl
-        // for `dyn ::realstd::io::LocalOutput`.
-        write(&mut local);
-        set_panic(Some(local));
+    if let Some(local) = set_output_capture(None) {
+        write(&mut *local.lock().unwrap_or_else(|e| e.into_inner()));
+        set_output_capture(Some(local));
     } else if let Some(mut out) = panic_output() {
         write(&mut out);
     }
diff --git a/library/std/src/sys/cloudabi/mod.rs b/library/std/src/sys/cloudabi/mod.rs
index 13f1bc8826e..b4a9246ca4e 100644
--- a/library/std/src/sys/cloudabi/mod.rs
+++ b/library/std/src/sys/cloudabi/mod.rs
@@ -66,3 +66,8 @@ pub fn hashmap_random_keys() -> (u64, u64) {
         v.assume_init()
     }
 }
+
+#[cfg_attr(feature = "backtrace", link(name = "unwind"))]
+#[link(name = "c")]
+#[link(name = "compiler_rt")]
+extern "C" {}
diff --git a/library/std/src/sys/sgx/abi/mem.rs b/library/std/src/sys/sgx/abi/mem.rs
index ffa234fccfe..da899773dbb 100644
--- a/library/std/src/sys/sgx/abi/mem.rs
+++ b/library/std/src/sys/sgx/abi/mem.rs
@@ -12,6 +12,18 @@ pub(crate) unsafe fn rel_ptr_mut<T>(offset: u64) -> *mut T {
 
 extern "C" {
     static ENCLAVE_SIZE: usize;
+    static HEAP_BASE: u64;
+    static HEAP_SIZE: usize;
+}
+
+/// Returns the base memory address of the heap
+pub(crate) fn heap_base() -> *const u8 {
+    unsafe { rel_ptr_mut(HEAP_BASE) }
+}
+
+/// Returns the size of the heap
+pub(crate) fn heap_size() -> usize {
+    unsafe { HEAP_SIZE }
 }
 
 // Do not remove inline: will result in relocation failure
diff --git a/library/std/src/sys/sgx/alloc.rs b/library/std/src/sys/sgx/alloc.rs
index 4559ea7cd25..4aea28cb83e 100644
--- a/library/std/src/sys/sgx/alloc.rs
+++ b/library/std/src/sys/sgx/alloc.rs
@@ -1,4 +1,7 @@
 use crate::alloc::{GlobalAlloc, Layout, System};
+use crate::ptr;
+use crate::sys::sgx::abi::mem as sgx_mem;
+use core::sync::atomic::{AtomicBool, Ordering};
 
 use super::waitqueue::SpinMutex;
 
@@ -10,7 +13,48 @@ use super::waitqueue::SpinMutex;
 // dlmalloc.c from C to Rust.
 #[cfg_attr(test, linkage = "available_externally")]
 #[export_name = "_ZN16__rust_internals3std3sys3sgx5alloc8DLMALLOCE"]
-static DLMALLOC: SpinMutex<dlmalloc::Dlmalloc> = SpinMutex::new(dlmalloc::DLMALLOC_INIT);
+static DLMALLOC: SpinMutex<dlmalloc::Dlmalloc<Sgx>> =
+    SpinMutex::new(dlmalloc::Dlmalloc::new_with_allocator(Sgx {}));
+
+struct Sgx;
+
+unsafe impl dlmalloc::Allocator for Sgx {
+    /// Allocs system resources
+    fn alloc(&self, _size: usize) -> (*mut u8, usize, u32) {
+        static INIT: AtomicBool = AtomicBool::new(false);
+
+        // No ordering requirement since this function is protected by the global lock.
+        if !INIT.swap(true, Ordering::Relaxed) {
+            (sgx_mem::heap_base() as _, sgx_mem::heap_size(), 0)
+        } else {
+            (ptr::null_mut(), 0, 0)
+        }
+    }
+
+    fn remap(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize, _can_move: bool) -> *mut u8 {
+        ptr::null_mut()
+    }
+
+    fn free_part(&self, _ptr: *mut u8, _oldsize: usize, _newsize: usize) -> bool {
+        false
+    }
+
+    fn free(&self, _ptr: *mut u8, _size: usize) -> bool {
+        return false;
+    }
+
+    fn can_release_part(&self, _flags: u32) -> bool {
+        false
+    }
+
+    fn allocates_zeros(&self) -> bool {
+        false
+    }
+
+    fn page_size(&self) -> usize {
+        0x1000
+    }
+}
 
 #[stable(feature = "alloc_system_type", since = "1.28.0")]
 unsafe impl GlobalAlloc for System {
diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs
index ac2fcfcb53f..1dc16ef0993 100644
--- a/library/std/src/sys/unix/kernel_copy.rs
+++ b/library/std/src/sys/unix/kernel_copy.rs
@@ -445,15 +445,15 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
     // We store the availability in a global to avoid unnecessary syscalls
     static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(true);
 
-    unsafe fn copy_file_range(
-        fd_in: libc::c_int,
-        off_in: *mut libc::loff_t,
-        fd_out: libc::c_int,
-        off_out: *mut libc::loff_t,
-        len: libc::size_t,
-        flags: libc::c_uint,
-    ) -> libc::c_long {
-        libc::syscall(libc::SYS_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags)
+    syscall! {
+        fn copy_file_range(
+            fd_in: libc::c_int,
+            off_in: *mut libc::loff_t,
+            fd_out: libc::c_int,
+            off_out: *mut libc::loff_t,
+            len: libc::size_t,
+            flags: libc::c_uint
+        ) -> libc::ssize_t
     }
 
     let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed);
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 7609afbdd76..f8a5ee89969 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -236,3 +236,55 @@ pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> {
 pub fn abort_internal() -> ! {
     unsafe { libc::abort() }
 }
+
+cfg_if::cfg_if! {
+    if #[cfg(target_os = "android")] {
+        #[link(name = "dl")]
+        #[link(name = "log")]
+        #[link(name = "gcc")]
+        extern "C" {}
+    } else if #[cfg(target_os = "freebsd")] {
+        #[link(name = "execinfo")]
+        #[link(name = "pthread")]
+        extern "C" {}
+    } else if #[cfg(target_os = "netbsd")] {
+        #[link(name = "pthread")]
+        #[link(name = "rt")]
+        extern "C" {}
+    } else if #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))] {
+        #[link(name = "pthread")]
+        extern "C" {}
+    } else if #[cfg(target_os = "solaris")] {
+        #[link(name = "socket")]
+        #[link(name = "posix4")]
+        #[link(name = "pthread")]
+        #[link(name = "resolv")]
+        extern "C" {}
+    } else if #[cfg(target_os = "illumos")] {
+        #[link(name = "socket")]
+        #[link(name = "posix4")]
+        #[link(name = "pthread")]
+        #[link(name = "resolv")]
+        #[link(name = "nsl")]
+        // Use libumem for the (malloc-compatible) allocator
+        #[link(name = "umem")]
+        extern "C" {}
+    } else if #[cfg(target_os = "macos")] {
+        #[link(name = "System")]
+        // res_init and friends require -lresolv on macOS/iOS.
+        // See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
+        #[link(name = "resolv")]
+        extern "C" {}
+    } else if #[cfg(target_os = "ios")] {
+        #[link(name = "System")]
+        #[link(name = "objc")]
+        #[link(name = "Security", kind = "framework")]
+        #[link(name = "Foundation", kind = "framework")]
+        #[link(name = "resolv")]
+        extern "C" {}
+    } else if #[cfg(target_os = "fuchsia")] {
+        #[link(name = "zircon")]
+        #[link(name = "fdio")]
+        extern "C" {}
+    }
+}
diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs
index eed6fbf13b7..38ddb41700c 100644
--- a/library/std/src/sys/unix/rand.rs
+++ b/library/std/src/sys/unix/rand.rs
@@ -25,10 +25,19 @@ mod imp {
     use crate::io::Read;
 
     #[cfg(any(target_os = "linux", target_os = "android"))]
-    fn getrandom(buf: &mut [u8]) -> libc::c_long {
-        unsafe {
-            libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
+    fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
+        // A weak symbol allows interposition, e.g. for perf measurements that want to
+        // disable randomness for consistency. Otherwise, we'll try a raw syscall.
+        // (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28)
+        syscall! {
+            fn getrandom(
+                buffer: *mut libc::c_void,
+                length: libc::size_t,
+                flags: libc::c_uint
+            ) -> libc::ssize_t
         }
+
+        unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) }
     }
 
     #[cfg(not(any(target_os = "linux", target_os = "android")))]
diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs
index f4b33a00f7c..53d95dca4cd 100644
--- a/library/std/src/sys/unix/weak.rs
+++ b/library/std/src/sys/unix/weak.rs
@@ -24,7 +24,7 @@
 use crate::ffi::CStr;
 use crate::marker;
 use crate::mem;
-use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::atomic::{self, AtomicUsize, Ordering};
 
 macro_rules! weak {
     (fn $name:ident($($t:ty),*) -> $ret:ty) => (
@@ -47,15 +47,49 @@ impl<F> Weak<F> {
     pub fn get(&self) -> Option<F> {
         assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
         unsafe {
-            if self.addr.load(Ordering::SeqCst) == 1 {
-                self.addr.store(fetch(self.name), Ordering::SeqCst);
-            }
-            match self.addr.load(Ordering::SeqCst) {
+            // Relaxed is fine here because we fence before reading through the
+            // pointer (see the comment below).
+            match self.addr.load(Ordering::Relaxed) {
+                1 => self.initialize(),
                 0 => None,
-                addr => Some(mem::transmute_copy::<usize, F>(&addr)),
+                addr => {
+                    let func = mem::transmute_copy::<usize, F>(&addr);
+                    // The caller is presumably going to read through this value
+                    // (by calling the function we've dlsymed). This means we'd
+                    // need to have loaded it with at least C11's consume
+                    // ordering in order to be guaranteed that the data we read
+                    // from the pointer isn't from before the pointer was
+                    // stored. Rust has no equivalent to memory_order_consume,
+                    // so we use an acquire fence (sorry, ARM).
+                    //
+                    // Now, in practice this likely isn't needed even on CPUs
+                    // where relaxed and consume mean different things. The
+                    // symbols we're loading are probably present (or not) at
+                    // init, and even if they aren't the runtime dynamic loader
+                    // is extremely likely have sufficient barriers internally
+                    // (possibly implicitly, for example the ones provided by
+                    // invoking `mprotect`).
+                    //
+                    // That said, none of that's *guaranteed*, and so we fence.
+                    atomic::fence(Ordering::Acquire);
+                    Some(func)
+                }
             }
         }
     }
+
+    // Cold because it should only happen during first-time initalization.
+    #[cold]
+    unsafe fn initialize(&self) -> Option<F> {
+        let val = fetch(self.name);
+        // This synchronizes with the acquire fence in `get`.
+        self.addr.store(val, Ordering::Release);
+
+        match val {
+            0 => None,
+            addr => Some(mem::transmute_copy::<usize, F>(&addr)),
+        }
+    }
 }
 
 unsafe fn fetch(name: &str) -> usize {
@@ -66,7 +100,7 @@ unsafe fn fetch(name: &str) -> usize {
     libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
 }
 
-#[cfg(not(target_os = "linux"))]
+#[cfg(not(any(target_os = "linux", target_os = "android")))]
 macro_rules! syscall {
     (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
         unsafe fn $name($($arg_name: $t),*) -> $ret {
@@ -84,7 +118,7 @@ macro_rules! syscall {
     )
 }
 
-#[cfg(target_os = "linux")]
+#[cfg(any(target_os = "linux", target_os = "android"))]
 macro_rules! syscall {
     (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
         unsafe fn $name($($arg_name:$t),*) -> $ret {
@@ -92,10 +126,18 @@ macro_rules! syscall {
             // (not paths).
             use libc::*;
 
-            syscall(
-                concat_idents!(SYS_, $name),
-                $($arg_name as c_long),*
-            ) as $ret
+            weak! { fn $name($($t),*) -> $ret }
+
+            // Use a weak symbol from libc when possible, allowing `LD_PRELOAD`
+            // interposition, but if it's not found just use a raw syscall.
+            if let Some(fun) = $name.get() {
+                fun($($arg_name),*)
+            } else {
+                syscall(
+                    concat_idents!(SYS_, $name),
+                    $($arg_name as c_long),*
+                ) as $ret
+            }
         }
     )
 }
diff --git a/library/std/src/sys/wasm/alloc.rs b/library/std/src/sys/wasm/alloc.rs
index b61a7872265..ef0ca3dd478 100644
--- a/library/std/src/sys/wasm/alloc.rs
+++ b/library/std/src/sys/wasm/alloc.rs
@@ -18,7 +18,7 @@
 
 use crate::alloc::{GlobalAlloc, Layout, System};
 
-static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
+static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::Dlmalloc::new();
 
 #[stable(feature = "alloc_system_type", since = "1.28.0")]
 unsafe impl GlobalAlloc for System {
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index 8c19cc78b09..c36c6196d79 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -270,3 +270,17 @@ pub fn abort_internal() -> ! {
     }
     crate::intrinsics::abort();
 }
+
+cfg_if::cfg_if! {
+    if #[cfg(target_vendor = "uwp")] {
+        #[link(name = "ws2_32")]
+        // For BCryptGenRandom
+        #[link(name = "bcrypt")]
+        extern "C" {}
+    } else {
+        #[link(name = "advapi32")]
+        #[link(name = "ws2_32")]
+        #[link(name = "userenv")]
+        extern "C" {}
+    }
+}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index fefaa77a2a1..5d65f960fcd 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -456,15 +456,15 @@ impl Builder {
         let my_packet: Arc<UnsafeCell<Option<Result<T>>>> = Arc::new(UnsafeCell::new(None));
         let their_packet = my_packet.clone();
 
-        let (stdout, stderr) = crate::io::clone_io();
+        let output_capture = crate::io::set_output_capture(None);
+        crate::io::set_output_capture(output_capture.clone());
 
         let main = move || {
             if let Some(name) = their_thread.cname() {
                 imp::Thread::set_name(name);
             }
 
-            crate::io::set_print(stdout);
-            crate::io::set_panic(stderr);
+            crate::io::set_output_capture(output_capture);
 
             // SAFETY: the stack guard passed is the one for the current thread.
             // This means the current thread's stack and the new thread's stack
diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs
index 8dd1a8ac0d2..61a04c46722 100644
--- a/library/std/tests/run-time-detect.rs
+++ b/library/std/tests/run-time-detect.rs
@@ -54,42 +54,62 @@ fn powerpc64_linux() {
 #[test]
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
 fn x86_all() {
+    // the below is the set of features we can test at runtime, but don't actually
+    // use to gate anything and are thus not part of the X86_ALLOWED_FEATURES list
+
+    println!("abm: {:?}", is_x86_feature_detected!("abm")); // this is a synonym for lzcnt but we test it anyways
+    println!("mmx: {:?}", is_x86_feature_detected!("mmx"));
+    println!("tsc: {:?}", is_x86_feature_detected!("tsc"));
+
+    // the below is in alphabetical order and matches
+    // the order of X86_ALLOWED_FEATURES in rustc_codegen_ssa's target_features.rs
+
+    println!("adx: {:?}", is_x86_feature_detected!("adx"));
     println!("aes: {:?}", is_x86_feature_detected!("aes"));
-    println!("pcmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq"));
+    println!("avx: {:?}", is_x86_feature_detected!("avx"));
+    println!("avx2: {:?}", is_x86_feature_detected!("avx2"));
+    println!("avx512bf16: {:?}", is_x86_feature_detected!("avx512bf16"));
+    println!("avx512bitalg: {:?}", is_x86_feature_detected!("avx512bitalg"));
+    println!("avx512bw: {:?}", is_x86_feature_detected!("avx512bw"));
+    println!("avx512cd: {:?}", is_x86_feature_detected!("avx512cd"));
+    println!("avx512dq: {:?}", is_x86_feature_detected!("avx512dq"));
+    println!("avx512er: {:?}", is_x86_feature_detected!("avx512er"));
+    println!("avx512f: {:?}", is_x86_feature_detected!("avx512f"));
+    println!("avx512gfni: {:?}", is_x86_feature_detected!("avx512gfni"));
+    println!("avx512ifma: {:?}", is_x86_feature_detected!("avx512ifma"));
+    println!("avx512pf: {:?}", is_x86_feature_detected!("avx512pf"));
+    println!("avx512vaes: {:?}", is_x86_feature_detected!("avx512vaes"));
+    println!("avx512vbmi: {:?}", is_x86_feature_detected!("avx512vbmi"));
+    println!("avx512vbmi2: {:?}", is_x86_feature_detected!("avx512vbmi2"));
+    println!("avx512vl: {:?}", is_x86_feature_detected!("avx512vl"));
+    println!("avx512vnni: {:?}", is_x86_feature_detected!("avx512vnni"));
+    println!("avx512vp2intersect: {:?}", is_x86_feature_detected!("avx512vp2intersect"));
+    println!("avx512vpclmulqdq: {:?}", is_x86_feature_detected!("avx512vpclmulqdq"));
+    println!("avx512vpopcntdq: {:?}", is_x86_feature_detected!("avx512vpopcntdq"));
+    println!("bmi1: {:?}", is_x86_feature_detected!("bmi1"));
+    println!("bmi2: {:?}", is_x86_feature_detected!("bmi2"));
+    println!("cmpxchg16b: {:?}", is_x86_feature_detected!("cmpxchg16b"));
+    println!("f16c: {:?}", is_x86_feature_detected!("f16c"));
+    println!("fma: {:?}", is_x86_feature_detected!("fma"));
+    println!("fxsr: {:?}", is_x86_feature_detected!("fxsr"));
+    println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt"));
+    //println!("movbe: {:?}", is_x86_feature_detected!("movbe")); // movbe is unsupported as a target feature
+    println!("pclmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq"));
+    println!("popcnt: {:?}", is_x86_feature_detected!("popcnt"));
     println!("rdrand: {:?}", is_x86_feature_detected!("rdrand"));
     println!("rdseed: {:?}", is_x86_feature_detected!("rdseed"));
-    println!("tsc: {:?}", is_x86_feature_detected!("tsc"));
-    println!("mmx: {:?}", is_x86_feature_detected!("mmx"));
+    println!("rtm: {:?}", is_x86_feature_detected!("rtm"));
+    println!("sha: {:?}", is_x86_feature_detected!("sha"));
     println!("sse: {:?}", is_x86_feature_detected!("sse"));
     println!("sse2: {:?}", is_x86_feature_detected!("sse2"));
     println!("sse3: {:?}", is_x86_feature_detected!("sse3"));
-    println!("ssse3: {:?}", is_x86_feature_detected!("ssse3"));
     println!("sse4.1: {:?}", is_x86_feature_detected!("sse4.1"));
     println!("sse4.2: {:?}", is_x86_feature_detected!("sse4.2"));
     println!("sse4a: {:?}", is_x86_feature_detected!("sse4a"));
-    println!("sha: {:?}", is_x86_feature_detected!("sha"));
-    println!("avx: {:?}", is_x86_feature_detected!("avx"));
-    println!("avx2: {:?}", is_x86_feature_detected!("avx2"));
-    println!("avx512f {:?}", is_x86_feature_detected!("avx512f"));
-    println!("avx512cd {:?}", is_x86_feature_detected!("avx512cd"));
-    println!("avx512er {:?}", is_x86_feature_detected!("avx512er"));
-    println!("avx512pf {:?}", is_x86_feature_detected!("avx512pf"));
-    println!("avx512bw {:?}", is_x86_feature_detected!("avx512bw"));
-    println!("avx512dq {:?}", is_x86_feature_detected!("avx512dq"));
-    println!("avx512vl {:?}", is_x86_feature_detected!("avx512vl"));
-    println!("avx512_ifma {:?}", is_x86_feature_detected!("avx512ifma"));
-    println!("avx512_vbmi {:?}", is_x86_feature_detected!("avx512vbmi"));
-    println!("avx512_vpopcntdq {:?}", is_x86_feature_detected!("avx512vpopcntdq"));
-    println!("fma: {:?}", is_x86_feature_detected!("fma"));
-    println!("bmi1: {:?}", is_x86_feature_detected!("bmi1"));
-    println!("bmi2: {:?}", is_x86_feature_detected!("bmi2"));
-    println!("abm: {:?}", is_x86_feature_detected!("abm"));
-    println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt"));
+    println!("ssse3: {:?}", is_x86_feature_detected!("ssse3"));
     println!("tbm: {:?}", is_x86_feature_detected!("tbm"));
-    println!("popcnt: {:?}", is_x86_feature_detected!("popcnt"));
-    println!("fxsr: {:?}", is_x86_feature_detected!("fxsr"));
     println!("xsave: {:?}", is_x86_feature_detected!("xsave"));
+    println!("xsavec: {:?}", is_x86_feature_detected!("xsavec"));
     println!("xsaveopt: {:?}", is_x86_feature_detected!("xsaveopt"));
     println!("xsaves: {:?}", is_x86_feature_detected!("xsaves"));
-    println!("xsavec: {:?}", is_x86_feature_detected!("xsavec"));
 }