diff options
| author | bors <bors@rust-lang.org> | 2024-09-10 08:16:37 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-09-10 08:16:37 +0000 |
| commit | 79d4cc9d7ce20cfe2300e33388bc1649bb3e7270 (patch) | |
| tree | 528f381b0514b059a536de840b9630879195b662 /library/std/src | |
| parent | 0225309e97bfc685ddc5643f44e122de803b73ad (diff) | |
| parent | 6e70bd4d07deb838af1471258742cf1564bce632 (diff) | |
Auto merge of #3876 - RalfJung:rustup, r=RalfJung
Rustup
Diffstat (limited to 'library/std/src')
| -rw-r--r-- | library/std/src/env.rs | 16 | ||||
| -rw-r--r-- | library/std/src/ffi/os_str.rs | 2 | ||||
| -rw-r--r-- | library/std/src/fs/tests.rs | 18 | ||||
| -rw-r--r-- | library/std/src/lib.rs | 1 | ||||
| -rw-r--r-- | library/std/src/os/unix/process.rs | 6 | ||||
| -rw-r--r-- | library/std/src/panicking.rs | 18 | ||||
| -rw-r--r-- | library/std/src/path.rs | 2 | ||||
| -rw-r--r-- | library/std/src/sync/condvar.rs | 8 | ||||
| -rw-r--r-- | library/std/src/sys/dbg.rs | 229 | ||||
| -rw-r--r-- | library/std/src/sys/mod.rs | 1 | ||||
| -rw-r--r-- | library/std/src/sys/pal/unix/linux/pidfd.rs | 11 | ||||
| -rw-r--r-- | library/std/src/sys/pal/wasi/fs.rs | 4 | ||||
| -rw-r--r-- | library/std/src/sys/pal/wasi/helpers.rs | 2 | ||||
| -rw-r--r-- | library/std/src/thread/mod.rs | 2 |
14 files changed, 270 insertions, 50 deletions
diff --git a/library/std/src/env.rs b/library/std/src/env.rs index e06a851658c..28916130b19 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -354,12 +354,8 @@ impl Error for VarError { /// } /// assert_eq!(env::var(key), Ok("VALUE".to_string())); /// ``` -#[cfg_attr(bootstrap, rustc_deprecated_safe_2024)] -#[cfg_attr( - not(bootstrap), - rustc_deprecated_safe_2024( - audit_that = "the environment access only happens in single-threaded code" - ) +#[rustc_deprecated_safe_2024( + audit_that = "the environment access only happens in single-threaded code" )] #[stable(feature = "env", since = "1.0.0")] pub unsafe fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) { @@ -424,12 +420,8 @@ pub unsafe fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) { /// } /// assert!(env::var(key).is_err()); /// ``` -#[cfg_attr(bootstrap, rustc_deprecated_safe_2024)] -#[cfg_attr( - not(bootstrap), - rustc_deprecated_safe_2024( - audit_that = "the environment access only happens in single-threaded code" - ) +#[rustc_deprecated_safe_2024( + audit_that = "the environment access only happens in single-threaded code" )] #[stable(feature = "env", since = "1.0.0")] pub unsafe fn remove_var<K: AsRef<OsStr>>(key: K) { diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 918eec2d0d8..99bea676e12 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -852,7 +852,7 @@ impl OsStr { /// Converts an `OsStr` to a <code>[Cow]<[str]></code>. /// - /// Any non-Unicode sequences are replaced with + /// Any non-UTF-8 sequences are replaced with /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. /// /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 13028c4c3b5..fb8dd2b0ca1 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1,7 +1,5 @@ use rand::RngCore; -#[cfg(target_os = "macos")] -use crate::ffi::{c_char, c_int}; use crate::fs::{self, File, FileTimes, OpenOptions}; use crate::io::prelude::*; use crate::io::{BorrowedBuf, ErrorKind, SeekFrom}; @@ -16,8 +14,6 @@ use crate::os::unix::fs::symlink as junction_point; use crate::os::windows::fs::{junction_point, symlink_dir, symlink_file, OpenOptionsExt}; use crate::path::Path; use crate::sync::Arc; -#[cfg(target_os = "macos")] -use crate::sys::weak::weak; use crate::sys_common::io::test::{tmpdir, TempDir}; use crate::time::{Duration, Instant, SystemTime}; use crate::{env, str, thread}; @@ -80,17 +76,6 @@ pub fn got_symlink_permission(tmpdir: &TempDir) -> bool { } } -#[cfg(target_os = "macos")] -fn able_to_not_follow_symlinks_while_hard_linking() -> bool { - weak!(fn linkat(c_int, *const c_char, c_int, *const c_char, c_int) -> c_int); - linkat.get().is_some() -} - -#[cfg(not(target_os = "macos"))] -fn able_to_not_follow_symlinks_while_hard_linking() -> bool { - return true; -} - #[test] fn file_test_io_smoke_test() { let message = "it's alright. have a good time"; @@ -1456,9 +1441,6 @@ fn symlink_hard_link() { if !got_symlink_permission(&tmpdir) { return; }; - if !able_to_not_follow_symlinks_while_hard_linking() { - return; - } // Create "file", a file. check!(fs::File::create(tmpdir.join("file"))); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 606d75668c4..60969af3e85 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -272,7 +272,6 @@ // // Language features: // tidy-alphabetical-start -#![cfg_attr(bootstrap, feature(min_exhaustive_patterns))] #![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 46202441d4e..9aadd949116 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -118,11 +118,7 @@ pub trait CommandExt: Sealed { /// [`pre_exec`]: CommandExt::pre_exec #[stable(feature = "process_exec", since = "1.15.0")] #[deprecated(since = "1.37.0", note = "should be unsafe, use `pre_exec` instead")] - #[cfg_attr(bootstrap, rustc_deprecated_safe_2024)] - #[cfg_attr( - not(bootstrap), - rustc_deprecated_safe_2024(audit_that = "the closure is async-signal-safe") - )] + #[rustc_deprecated_safe_2024(audit_that = "the closure is async-signal-safe")] unsafe fn before_exec<F>(&mut self, f: F) -> &mut process::Command where F: FnMut() -> io::Result<()> + Send + Sync + 'static, diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 1c972d38100..336e34d7b95 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -23,8 +23,8 @@ use crate::mem::{self, ManuallyDrop}; use crate::panic::{BacktraceStyle, PanicHookInfo}; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{PoisonError, RwLock}; -use crate::sys::backtrace; use crate::sys::stdio::panic_output; +use crate::sys::{backtrace, dbg}; use crate::{fmt, intrinsics, process, thread}; // Binary interface to the panic runtime that the standard library depends on. @@ -859,6 +859,14 @@ pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! { #[cfg_attr(not(test), rustc_std_internal_symbol)] #[cfg(not(feature = "panic_immediate_abort"))] fn rust_panic(msg: &mut dyn PanicPayload) -> ! { + // Break into the debugger if it is attached. + // The return value is not currently used. + // + // This function isn't used anywhere else, and + // using inside `#[panic_handler]` doesn't seem + // to count, so a warning is issued. + let _ = dbg::breakpoint_if_debugging(); + let code = unsafe { __rust_start_panic(msg) }; rtabort!("failed to initiate panic, error {code}") } @@ -866,6 +874,14 @@ fn rust_panic(msg: &mut dyn PanicPayload) -> ! { #[cfg_attr(not(test), rustc_std_internal_symbol)] #[cfg(feature = "panic_immediate_abort")] fn rust_panic(_: &mut dyn PanicPayload) -> ! { + // Break into the debugger if it is attached. + // The return value is not currently used. + // + // This function isn't used anywhere else, and + // using inside `#[panic_handler]` doesn't seem + // to count, so a warning is issued. + let _ = dbg::breakpoint_if_debugging(); + unsafe { crate::intrinsics::abort(); } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 9eaa0e01c2c..506ad445b6b 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2200,7 +2200,7 @@ impl Path { /// Converts a `Path` to a [`Cow<str>`]. /// - /// Any non-Unicode sequences are replaced with + /// Any non-UTF-8 sequences are replaced with /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. /// /// [U+FFFD]: super::char::REPLACEMENT_CHARACTER diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index 08d46f356d9..e41cbc1a65c 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -195,8 +195,11 @@ impl Condvar { if poisoned { Err(PoisonError::new(guard)) } else { Ok(guard) } } - /// Blocks the current thread until this condition variable receives a - /// notification and the provided condition is false. + /// Blocks the current thread until the provided condition becomes false. + /// + /// `condition` is checked immediately; if not met (returns `true`), this + /// will [`wait`] for the next notification then check again. This repeats + /// until `condition` returns `false`, in which case this function returns. /// /// This function will atomically unlock the mutex specified (represented by /// `guard`) and block the current thread. This means that any calls @@ -210,6 +213,7 @@ impl Condvar { /// poisoned when this thread re-acquires the lock. For more information, /// see information about [poisoning] on the [`Mutex`] type. /// + /// [`wait`]: Self::wait /// [`notify_one`]: Self::notify_one /// [`notify_all`]: Self::notify_all /// [poisoning]: super::Mutex#poisoning diff --git a/library/std/src/sys/dbg.rs b/library/std/src/sys/dbg.rs new file mode 100644 index 00000000000..a6e78db3c86 --- /dev/null +++ b/library/std/src/sys/dbg.rs @@ -0,0 +1,229 @@ +//! Debugging aids. + +/// Presence of a debugger. The debugger being concerned +/// is expected to use the OS API to debug this process. +#[derive(Copy, Clone, Debug)] +#[allow(unused)] +pub(crate) enum DebuggerPresence { + /// The debugger is attached to this process. + Detected, + /// The debugger is not attached to this process. + NotDetected, +} + +#[cfg(target_os = "windows")] +mod os { + use super::DebuggerPresence; + + #[link(name = "kernel32")] + extern "system" { + fn IsDebuggerPresent() -> i32; + } + + pub(super) fn is_debugger_present() -> Option<DebuggerPresence> { + // SAFETY: No state is shared between threads. The call reads + // a field from the Thread Environment Block using the OS API + // as required by the documentation. + if unsafe { IsDebuggerPresent() } != 0 { + Some(DebuggerPresence::Detected) + } else { + Some(DebuggerPresence::NotDetected) + } + } +} + +#[cfg(any(target_vendor = "apple", target_os = "freebsd"))] +mod os { + use libc::{c_int, sysctl, CTL_KERN, KERN_PROC, KERN_PROC_PID}; + + use super::DebuggerPresence; + use crate::io::{Cursor, Read, Seek, SeekFrom}; + use crate::process; + + const P_TRACED: i32 = 0x00000800; + + // The assumption is that the kernel structures available to the + // user space may not shrink or repurpose the existing fields over + // time. The kernels normally adhere to that for the backward + // compatibility of the user space. + + // The macOS 14.5 SDK comes with a header `MacOSX14.5.sdk/usr/include/sys/sysctl.h` + // that defines `struct kinfo_proc` be of `648` bytes on the 64-bit system. That has + // not changed since macOS 10.13 (released in 2017) at least, validated by building + // a C program in XCode while changing the build target. Apple provides this example + // for reference: https://developer.apple.com/library/archive/qa/qa1361/_index.html. + #[cfg(target_vendor = "apple")] + const KINFO_PROC_SIZE: usize = if cfg!(target_pointer_width = "64") { 648 } else { 492 }; + #[cfg(target_vendor = "apple")] + const KINFO_PROC_FLAGS_OFFSET: u64 = if cfg!(target_pointer_width = "64") { 32 } else { 16 }; + + // Works for FreeBSD stable (13.3, 13.4) and current (14.0, 14.1). + // The size of the structure has stayed the same for a long time, + // at least since 2005: + // https://lists.freebsd.org/pipermail/freebsd-stable/2005-November/019899.html + #[cfg(target_os = "freebsd")] + const KINFO_PROC_SIZE: usize = if cfg!(target_pointer_width = "64") { 1088 } else { 768 }; + #[cfg(target_os = "freebsd")] + const KINFO_PROC_FLAGS_OFFSET: u64 = if cfg!(target_pointer_width = "64") { 368 } else { 296 }; + + pub(super) fn is_debugger_present() -> Option<DebuggerPresence> { + debug_assert_ne!(KINFO_PROC_SIZE, 0); + + let mut flags = [0u8; 4]; // `ki_flag` under FreeBSD and `p_flag` under macOS. + let mut mib = [CTL_KERN, KERN_PROC, KERN_PROC_PID, process::id() as c_int]; + let mut info_size = KINFO_PROC_SIZE; + let mut kinfo_proc = [0u8; KINFO_PROC_SIZE]; + + // SAFETY: No state is shared with other threads. The sysctl call + // is safe according to the documentation. + if unsafe { + sysctl( + mib.as_mut_ptr(), + mib.len() as u32, + kinfo_proc.as_mut_ptr().cast(), + &mut info_size, + core::ptr::null_mut(), + 0, + ) + } != 0 + { + return None; + } + debug_assert_eq!(info_size, KINFO_PROC_SIZE); + + let mut reader = Cursor::new(kinfo_proc); + reader.seek(SeekFrom::Start(KINFO_PROC_FLAGS_OFFSET)).ok()?; + reader.read_exact(&mut flags).ok()?; + // Just in case, not limiting this to the little-endian systems. + let flags = i32::from_ne_bytes(flags); + + if flags & P_TRACED != 0 { + Some(DebuggerPresence::Detected) + } else { + Some(DebuggerPresence::NotDetected) + } + } +} + +#[cfg(target_os = "linux")] +mod os { + use super::DebuggerPresence; + use crate::fs::File; + use crate::io::Read; + + pub(super) fn is_debugger_present() -> Option<DebuggerPresence> { + // This function is crafted with the following goals: + // * Memory efficiency: It avoids crashing the panicking process due to + // out-of-memory (OOM) conditions by not using large heap buffers or + // allocating significant stack space, which could lead to stack overflow. + // * Minimal binary size: The function uses a minimal set of facilities + // from the standard library to avoid increasing the resulting binary size. + // + // To achieve these goals, the function does not use `[std::io::BufReader]` + // and instead reads the file byte by byte using a sliding window approach. + // It's important to note that the "/proc/self/status" pseudo-file is synthesized + // by the Virtual File System (VFS), meaning it is not read from a slow or + // non-volatile storage medium so buffering might not be as beneficial because + // all data is read from memory, though this approach does incur a syscall for + // each byte read. + // + // We cannot make assumptions about the file size or the position of the + // target prefix ("TracerPid:"), so the function does not use + // `[std::fs::read_to_string]` thus not employing UTF-8 to ASCII checking, + // conversion, or parsing as we're looking for an ASCII prefix. + // + // These condiderations make the function deviate from the familiar concise pattern + // of searching for a string in a text file. + + fn read_byte(file: &mut File) -> Option<u8> { + let mut buffer = [0]; + file.read_exact(&mut buffer).ok()?; + Some(buffer[0]) + } + + // The ASCII prefix of the datum we're interested in. + const TRACER_PID: &[u8] = b"TracerPid:\t"; + + let mut file = File::open("/proc/self/status").ok()?; + let mut matched = 0; + + // Look for the `TRACER_PID` prefix. + while let Some(byte) = read_byte(&mut file) { + if byte == TRACER_PID[matched] { + matched += 1; + if matched == TRACER_PID.len() { + break; + } + } else { + matched = 0; + } + } + + // Was the prefix found? + if matched != TRACER_PID.len() { + return None; + } + + // It was; get the ASCII representation of the first digit + // of the PID. That is enough to see if there is a debugger + // attached as the kernel does not pad the PID on the left + // with the leading zeroes. + let byte = read_byte(&mut file)?; + if byte.is_ascii_digit() && byte != b'0' { + Some(DebuggerPresence::Detected) + } else { + Some(DebuggerPresence::NotDetected) + } + } +} + +#[cfg(not(any( + target_os = "windows", + target_vendor = "apple", + target_os = "freebsd", + target_os = "linux" +)))] +mod os { + pub(super) fn is_debugger_present() -> Option<super::DebuggerPresence> { + None + } +} + +/// Detect the debugger presence. +/// +/// The code does not try to detect the debugger at all costs (e.g., when anti-debugger +/// tricks are at play), it relies on the interfaces provided by the OS. +/// +/// Return value: +/// * `None`: it's not possible to conclude whether the debugger is attached to this +/// process or not. When checking for the presence of the debugger, the detection logic +/// encountered an issue, such as the OS API throwing an error or the feature not being +/// implemented. +/// * `Some(DebuggerPresence::Detected)`: yes, the debugger is attached +/// to this process. +/// * `Some(DebuggerPresence::NotDetected)`: no, the debugger is not +/// attached to this process. +pub(crate) fn is_debugger_present() -> Option<DebuggerPresence> { + if cfg!(miri) { None } else { os::is_debugger_present() } +} + +/// Execute the breakpoint instruction if the debugger presence is detected. +/// Useful for breaking into the debugger without the need to set a breakpoint +/// in the debugger. +/// +/// Note that there is a race between attaching or detaching the debugger, and running the +/// breakpoint instruction. This is nonetheless memory-safe, like [`crate::process::abort`] +/// is. In case the debugger is attached and the function is about +/// to run the breakpoint instruction yet right before that the debugger detaches, the +/// process will crash due to running the breakpoint instruction and the debugger not +/// handling the trap exception. +pub(crate) fn breakpoint_if_debugging() -> Option<DebuggerPresence> { + let debugger_present = is_debugger_present(); + if let Some(DebuggerPresence::Detected) = debugger_present { + // SAFETY: Executing the breakpoint instruction. No state is shared + // or modified by this code. + unsafe { core::intrinsics::breakpoint() }; + } + + debugger_present +} diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 1ef17dd530f..96d6f2c87c4 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -11,6 +11,7 @@ mod personality; pub mod anonymous_pipe; pub mod backtrace; pub mod cmath; +pub mod dbg; pub mod exit_guard; pub mod os_str; pub mod path; diff --git a/library/std/src/sys/pal/unix/linux/pidfd.rs b/library/std/src/sys/pal/unix/linux/pidfd.rs index 7474f80e94f..78744430f3b 100644 --- a/library/std/src/sys/pal/unix/linux/pidfd.rs +++ b/library/std/src/sys/pal/unix/linux/pidfd.rs @@ -13,7 +13,7 @@ pub(crate) struct PidFd(FileDesc); impl PidFd { pub fn kill(&self) -> io::Result<()> { - return cvt(unsafe { + cvt(unsafe { libc::syscall( libc::SYS_pidfd_send_signal, self.0.as_raw_fd(), @@ -22,7 +22,7 @@ impl PidFd { 0, ) }) - .map(drop); + .map(drop) } pub fn wait(&self) -> io::Result<ExitStatus> { @@ -30,7 +30,7 @@ impl PidFd { cvt(unsafe { libc::waitid(libc::P_PIDFD, self.0.as_raw_fd() as u32, &mut siginfo, libc::WEXITED) })?; - return Ok(ExitStatus::from_waitid_siginfo(siginfo)); + Ok(ExitStatus::from_waitid_siginfo(siginfo)) } pub fn try_wait(&self) -> io::Result<Option<ExitStatus>> { @@ -45,9 +45,10 @@ impl PidFd { ) })?; if unsafe { siginfo.si_pid() } == 0 { - return Ok(None); + Ok(None) + } else { + Ok(Some(ExitStatus::from_waitid_siginfo(siginfo))) } - return Ok(Some(ExitStatus::from_waitid_siginfo(siginfo))); } } diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index 88b1e543ec7..e1c61cae9f8 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -265,7 +265,7 @@ impl OpenOptions { pub fn new() -> OpenOptions { let mut base = OpenOptions::default(); base.dirflags = wasi::LOOKUPFLAGS_SYMLINK_FOLLOW; - return base; + base } pub fn read(&mut self, read: bool) { @@ -382,7 +382,7 @@ impl OpenOptions { base |= wasi::RIGHTS_PATH_UNLINK_FILE; base |= wasi::RIGHTS_POLL_FD_READWRITE; - return base; + base } fn rights_inheriting(&self) -> wasi::Rights { diff --git a/library/std/src/sys/pal/wasi/helpers.rs b/library/std/src/sys/pal/wasi/helpers.rs index d047bf2fce8..37ef17858cb 100644 --- a/library/std/src/sys/pal/wasi/helpers.rs +++ b/library/std/src/sys/pal/wasi/helpers.rs @@ -115,7 +115,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { let len = mem::size_of_val(&ret); wasi::random_get(base, len).expect("random_get failure"); } - return ret; + ret } #[inline] diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index e29c28f3c7e..0fc63c5081b 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -432,7 +432,7 @@ impl Builder { /// ``` /// /// [`io::Result`]: crate::io::Result - #[stable(feature = "thread_spawn_unchecked", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "thread_spawn_unchecked", since = "1.82.0")] pub unsafe fn spawn_unchecked<F, T>(self, f: F) -> io::Result<JoinHandle<T>> where F: FnOnce() -> T, |
