about summary refs log tree commit diff
path: root/library/std/src/sys
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys')
-rw-r--r--library/std/src/sys/pal/uefi/process.rs68
-rw-r--r--library/std/src/sys/pal/unix/os.rs78
-rw-r--r--library/std/src/sys/pal/unix/os/tests.rs25
-rw-r--r--library/std/src/sys/random/arc4random.rs2
-rw-r--r--library/std/src/sys/sync/once/queue.rs9
-rw-r--r--library/std/src/sys/sync/rwlock/queue.rs6
6 files changed, 162 insertions, 26 deletions
diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs
index 0cc9cecb89d..1b83f4b0aee 100644
--- a/library/std/src/sys/pal/uefi/process.rs
+++ b/library/std/src/sys/pal/uefi/process.rs
@@ -18,6 +18,7 @@ use crate::{fmt, io};
 #[derive(Debug)]
 pub struct Command {
     prog: OsString,
+    args: Vec<OsString>,
     stdout: Option<Stdio>,
     stderr: Option<Stdio>,
 }
@@ -39,12 +40,11 @@ pub enum Stdio {
 
 impl Command {
     pub fn new(program: &OsStr) -> Command {
-        Command { prog: program.to_os_string(), stdout: None, stderr: None }
+        Command { prog: program.to_os_string(), args: Vec::new(), stdout: None, stderr: None }
     }
 
-    // FIXME: Implement arguments as reverse of parsing algorithm
-    pub fn arg(&mut self, _arg: &OsStr) {
-        panic!("unsupported")
+    pub fn arg(&mut self, arg: &OsStr) {
+        self.args.push(arg.to_os_string());
     }
 
     pub fn env_mut(&mut self) -> &mut CommandEnv {
@@ -72,7 +72,7 @@ impl Command {
     }
 
     pub fn get_args(&self) -> CommandArgs<'_> {
-        panic!("unsupported")
+        CommandArgs { iter: self.args.iter() }
     }
 
     pub fn get_envs(&self) -> CommandEnvs<'_> {
@@ -116,6 +116,12 @@ impl Command {
     pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
         let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
 
+        // UEFI adds the bin name by default
+        if !self.args.is_empty() {
+            let args = uefi_command_internal::create_args(&self.prog, &self.args);
+            cmd.set_args(args);
+        }
+
         // Setup Stdout
         let stdout = self.stdout.unwrap_or(Stdio::MakePipe);
         let stdout = Self::create_pipe(stdout)?;
@@ -315,7 +321,7 @@ mod uefi_command_internal {
         stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
         stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
         st: OwnedTable<r_efi::efi::SystemTable>,
-        args: Option<Vec<u16>>,
+        args: Option<(*mut u16, usize)>,
     }
 
     impl Image {
@@ -449,20 +455,20 @@ mod uefi_command_internal {
             }
         }
 
-        pub fn set_args(&mut self, args: &OsStr) {
+        pub fn set_args(&mut self, args: Box<[u16]>) {
             let loaded_image: NonNull<loaded_image::Protocol> =
                 helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
 
-            let mut args = args.encode_wide().collect::<Vec<u16>>();
-            let args_size = (crate::mem::size_of::<u16>() * args.len()) as u32;
+            let len = args.len();
+            let args_size: u32 = crate::mem::size_of_val(&args).try_into().unwrap();
+            let ptr = Box::into_raw(args).as_mut_ptr();
 
             unsafe {
-                (*loaded_image.as_ptr()).load_options =
-                    args.as_mut_ptr() as *mut crate::ffi::c_void;
+                (*loaded_image.as_ptr()).load_options = ptr as *mut crate::ffi::c_void;
                 (*loaded_image.as_ptr()).load_options_size = args_size;
             }
 
-            self.args = Some(args);
+            self.args = Some((ptr, len));
         }
 
         fn update_st_crc32(&mut self) -> io::Result<()> {
@@ -502,6 +508,10 @@ mod uefi_command_internal {
                     ((*bt.as_ptr()).unload_image)(self.handle.as_ptr());
                 }
             }
+
+            if let Some((ptr, len)) = self.args {
+                let _ = unsafe { Box::from_raw(crate::ptr::slice_from_raw_parts_mut(ptr, len)) };
+            }
         }
     }
 
@@ -681,4 +691,38 @@ mod uefi_command_internal {
             }
         }
     }
+
+    pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> {
+        const QUOTE: u16 = 0x0022;
+        const SPACE: u16 = 0x0020;
+        const CARET: u16 = 0x005e;
+        const NULL: u16 = 0;
+
+        // This is the lower bound on the final length under the assumption that
+        // the arguments only contain ASCII characters.
+        let mut res = Vec::with_capacity(args.iter().map(|arg| arg.len() + 3).sum());
+
+        // Wrap program name in quotes to avoid any problems
+        res.push(QUOTE);
+        res.extend(prog.encode_wide());
+        res.push(QUOTE);
+        res.push(SPACE);
+
+        for arg in args {
+            // Wrap the argument in quotes to be treat as single arg
+            res.push(QUOTE);
+            for c in arg.encode_wide() {
+                // CARET in quotes is used to escape CARET or QUOTE
+                if c == QUOTE || c == CARET {
+                    res.push(CARET);
+                }
+                res.push(c);
+            }
+            res.push(QUOTE);
+
+            res.push(SPACE);
+        }
+
+        res.into_boxed_slice()
+    }
 }
diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs
index f983d174ed6..f207131ddf3 100644
--- a/library/std/src/sys/pal/unix/os.rs
+++ b/library/std/src/sys/pal/unix/os.rs
@@ -698,12 +698,82 @@ pub fn page_size() -> usize {
     unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
 }
 
+// Returns the value for [`confstr(key, ...)`][posix_confstr]. Currently only
+// used on Darwin, but should work on any unix (in case we need to get
+// `_CS_PATH` or `_CS_V[67]_ENV` in the future).
+//
+// [posix_confstr]:
+//     https://pubs.opengroup.org/onlinepubs/9699919799/functions/confstr.html
+//
+// FIXME: Support `confstr` in Miri.
+#[cfg(all(target_vendor = "apple", not(miri)))]
+fn confstr(key: c_int, size_hint: Option<usize>) -> io::Result<OsString> {
+    let mut buf: Vec<u8> = Vec::with_capacity(0);
+    let mut bytes_needed_including_nul = size_hint
+        .unwrap_or_else(|| {
+            // Treat "None" as "do an extra call to get the length". In theory
+            // we could move this into the loop below, but it's hard to do given
+            // that it isn't 100% clear if it's legal to pass 0 for `len` when
+            // the buffer isn't null.
+            unsafe { libc::confstr(key, core::ptr::null_mut(), 0) }
+        })
+        .max(1);
+    // If the value returned by `confstr` is greater than the len passed into
+    // it, then the value was truncated, meaning we need to retry. Note that
+    // while `confstr` results don't seem to change for a process, it's unclear
+    // if this is guaranteed anywhere, so looping does seem required.
+    while bytes_needed_including_nul > buf.capacity() {
+        // We write into the spare capacity of `buf`. This lets us avoid
+        // changing buf's `len`, which both simplifies `reserve` computation,
+        // allows working with `Vec<u8>` instead of `Vec<MaybeUninit<u8>>`, and
+        // may avoid a copy, since the Vec knows that none of the bytes are needed
+        // when reallocating (well, in theory anyway).
+        buf.reserve(bytes_needed_including_nul);
+        // `confstr` returns
+        // - 0 in the case of errors: we break and return an error.
+        // - The number of bytes written, iff the provided buffer is enough to
+        //   hold the entire value: we break and return the data in `buf`.
+        // - Otherwise, the number of bytes needed (including nul): we go
+        //   through the loop again.
+        bytes_needed_including_nul =
+            unsafe { libc::confstr(key, buf.as_mut_ptr().cast::<c_char>(), buf.capacity()) };
+    }
+    // `confstr` returns 0 in the case of an error.
+    if bytes_needed_including_nul == 0 {
+        return Err(io::Error::last_os_error());
+    }
+    // Safety: `confstr(..., buf.as_mut_ptr(), buf.capacity())` returned a
+    // non-zero value, meaning `bytes_needed_including_nul` bytes were
+    // initialized.
+    unsafe {
+        buf.set_len(bytes_needed_including_nul);
+        // Remove the NUL-terminator.
+        let last_byte = buf.pop();
+        // ... and smoke-check that it *was* a NUL-terminator.
+        assert_eq!(last_byte, Some(0), "`confstr` provided a string which wasn't nul-terminated");
+    };
+    Ok(OsString::from_vec(buf))
+}
+
+#[cfg(all(target_vendor = "apple", not(miri)))]
+fn darwin_temp_dir() -> PathBuf {
+    confstr(libc::_CS_DARWIN_USER_TEMP_DIR, Some(64)).map(PathBuf::from).unwrap_or_else(|_| {
+        // It failed for whatever reason (there are several possible reasons),
+        // so return the global one.
+        PathBuf::from("/tmp")
+    })
+}
+
 pub fn temp_dir() -> PathBuf {
     crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
-        if cfg!(target_os = "android") {
-            PathBuf::from("/data/local/tmp")
-        } else {
-            PathBuf::from("/tmp")
+        cfg_if::cfg_if! {
+            if #[cfg(all(target_vendor = "apple", not(miri)))] {
+                darwin_temp_dir()
+            } else if #[cfg(target_os = "android")] {
+                PathBuf::from("/data/local/tmp")
+            } else {
+                PathBuf::from("/tmp")
+            }
         }
     })
 }
diff --git a/library/std/src/sys/pal/unix/os/tests.rs b/library/std/src/sys/pal/unix/os/tests.rs
index efc29955b05..63a1cc1e94a 100644
--- a/library/std/src/sys/pal/unix/os/tests.rs
+++ b/library/std/src/sys/pal/unix/os/tests.rs
@@ -21,3 +21,28 @@ fn test_parse_glibc_version() {
         assert_eq!(parsed, super::parse_glibc_version(version_str));
     }
 }
+
+// Smoke check `confstr`, do it for several hint values, to ensure our resizing
+// logic is correct.
+#[test]
+#[cfg(all(target_vendor = "apple", not(miri)))]
+fn test_confstr() {
+    for key in [libc::_CS_DARWIN_USER_TEMP_DIR, libc::_CS_PATH] {
+        let value_nohint = super::confstr(key, None).unwrap_or_else(|e| {
+            panic!("confstr({key}, None) failed: {e:?}");
+        });
+        let end = (value_nohint.len() + 1) * 2;
+        for hint in 0..end {
+            assert_eq!(
+                super::confstr(key, Some(hint)).as_deref().ok(),
+                Some(&*value_nohint),
+                "confstr({key}, Some({hint})) failed",
+            );
+        }
+    }
+    // Smoke check that we don't loop forever or something if the input was not valid.
+    for hint in [None, Some(0), Some(1)] {
+        let hopefully_invalid = 123456789_i32;
+        assert!(super::confstr(hopefully_invalid, hint).is_err());
+    }
+}
diff --git a/library/std/src/sys/random/arc4random.rs b/library/std/src/sys/random/arc4random.rs
index ffabaafbee8..32467e9ebaa 100644
--- a/library/std/src/sys/random/arc4random.rs
+++ b/library/std/src/sys/random/arc4random.rs
@@ -12,7 +12,6 @@
 #[cfg(not(any(
     target_os = "haiku",
     target_os = "illumos",
-    target_os = "rtems",
     target_os = "solaris",
     target_os = "vita",
 )))]
@@ -22,7 +21,6 @@ use libc::arc4random_buf;
 #[cfg(any(
     target_os = "haiku", // See https://git.haiku-os.org/haiku/tree/headers/compatibility/bsd/stdlib.h
     target_os = "illumos", // See https://www.illumos.org/man/3C/arc4random
-    target_os = "rtems", // See https://docs.rtems.org/branches/master/bsp-howto/getentropy.html
     target_os = "solaris", // See https://docs.oracle.com/cd/E88353_01/html/E37843/arc4random-3c.html
     target_os = "vita", // See https://github.com/vitasdk/newlib/blob/b89e5bc183b516945f9ee07eef483ecb916e45ff/newlib/libc/include/stdlib.h#L74
 ))]
diff --git a/library/std/src/sys/sync/once/queue.rs b/library/std/src/sys/sync/once/queue.rs
index 177d0d7744a..87837915b39 100644
--- a/library/std/src/sys/sync/once/queue.rs
+++ b/library/std/src/sys/sync/once/queue.rs
@@ -93,7 +93,7 @@ const QUEUE_MASK: usize = !STATE_MASK;
 // use interior mutability.
 #[repr(align(4))] // Ensure the two lower bits are free to use as state bits.
 struct Waiter {
-    thread: Cell<Option<Thread>>,
+    thread: Thread,
     signaled: AtomicBool,
     next: Cell<*const Waiter>,
 }
@@ -238,7 +238,7 @@ fn wait(
     return_on_poisoned: bool,
 ) -> StateAndQueue {
     let node = &Waiter {
-        thread: Cell::new(Some(thread::current())),
+        thread: thread::current_or_unnamed(),
         signaled: AtomicBool::new(false),
         next: Cell::new(ptr::null()),
     };
@@ -277,7 +277,8 @@ fn wait(
             // can park ourselves, the result could be this thread never gets
             // unparked. Luckily `park` comes with the guarantee that if it got
             // an `unpark` just before on an unparked thread it does not park.
-            thread::park();
+            // SAFETY: we retrieved this handle on the current thread above.
+            unsafe { node.thread.park() }
         }
 
         return state_and_queue.load(Acquire);
@@ -309,7 +310,7 @@ impl Drop for WaiterQueue<'_> {
             let mut queue = to_queue(current);
             while !queue.is_null() {
                 let next = (*queue).next.get();
-                let thread = (*queue).thread.take().unwrap();
+                let thread = (*queue).thread.clone();
                 (*queue).signaled.store(true, Release);
                 thread.unpark();
                 queue = next;
diff --git a/library/std/src/sys/sync/rwlock/queue.rs b/library/std/src/sys/sync/rwlock/queue.rs
index 51330f8fafe..bd15f8ee952 100644
--- a/library/std/src/sys/sync/rwlock/queue.rs
+++ b/library/std/src/sys/sync/rwlock/queue.rs
@@ -118,7 +118,7 @@ use crate::mem;
 use crate::ptr::{self, NonNull, null_mut, without_provenance_mut};
 use crate::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed, Release};
 use crate::sync::atomic::{AtomicBool, AtomicPtr};
-use crate::thread::{self, Thread, ThreadId};
+use crate::thread::{self, Thread};
 
 /// The atomic lock state.
 type AtomicState = AtomicPtr<()>;
@@ -217,9 +217,7 @@ impl Node {
     /// Prepare this node for waiting.
     fn prepare(&mut self) {
         // Fall back to creating an unnamed `Thread` handle to allow locking in TLS destructors.
-        self.thread.get_or_init(|| {
-            thread::try_current().unwrap_or_else(|| Thread::new_unnamed(ThreadId::new()))
-        });
+        self.thread.get_or_init(thread::current_or_unnamed);
         self.completed = AtomicBool::new(false);
     }