From 9c5f11fbc8dbd09678659cbadaf2d995108ec5e3 Mon Sep 17 00:00:00 2001 From: Jacob Lorentzon <4ldo2@protonmail.com> Date: Sun, 21 Sep 2025 14:36:12 +0200 Subject: [PATCH] Add `Out` wrapper --- src/header/dirent/mod.rs | 3 +- src/header/netdb/lookup.rs | 17 +++- src/header/stdio/mod.rs | 4 +- src/header/stdlib/mod.rs | 7 +- src/header/sys_resource/mod.rs | 5 +- src/header/sys_stat/mod.rs | 8 ++ src/header/sys_statvfs/mod.rs | 3 + src/header/sys_time/mod.rs | 5 +- src/header/sys_wait/mod.rs | 4 +- src/header/time/mod.rs | 11 ++- src/header/unistd/mod.rs | 41 +++++--- src/ld_so/linker.rs | 5 +- src/lib.rs | 2 + src/out.rs | 167 +++++++++++++++++++++++++++++++++ src/platform/linux/mod.rs | 166 +++++++++++++++++++++----------- src/platform/pal/mod.rs | 43 ++++----- src/platform/redox/extra.rs | 9 +- src/platform/redox/libredox.rs | 13 ++- src/platform/redox/mod.rs | 130 ++++++++++++------------- src/platform/redox/path.rs | 15 ++- src/sync/mod.rs | 6 +- 21 files changed, 469 insertions(+), 195 deletions(-) create mode 100644 src/out.rs diff --git a/src/header/dirent/mod.rs b/src/header/dirent/mod.rs index cace3f8195..f841bc48ad 100644 --- a/src/header/dirent/mod.rs +++ b/src/header/dirent/mod.rs @@ -13,6 +13,7 @@ use crate::{ error::{Errno, ResultExt, ResultExtPtrMut}, fs::File, header::{fcntl, stdlib, string}, + out::Out, platform::{self, types::*, Pal, Sys}, }; @@ -49,7 +50,7 @@ impl DIR { pub fn from_fd(fd: c_int) -> Result, Errno> { let mut stat = sys_stat::stat::default(); unsafe { - Sys::fstat(fd, &mut stat)?; + Sys::fstat(fd, Out::from_mut(&mut stat))?; } if (stat.st_mode & sys_stat::S_IFMT) != sys_stat::S_IFDIR { return Err(Errno(ENOTDIR)); diff --git a/src/header/netdb/lookup.rs b/src/header/netdb/lookup.rs index 1f83e8f682..7ab46ae5a8 100644 --- a/src/header/netdb/lookup.rs +++ b/src/header/netdb/lookup.rs @@ -5,7 +5,10 @@ use alloc::{ }; use core::mem; -use crate::platform::{types::*, Pal, Sys}; +use crate::{ + out::Out, + platform::{types::*, Pal, Sys}, +}; use crate::header::{ errno::*, @@ -50,7 +53,10 @@ pub fn lookup_host(host: &str) -> Result { if let Some(dns_addr) = parse_ipv4_string(&dns_string) { let mut timespec = timespec::default(); unsafe { - Sys::clock_gettime(time::constants::CLOCK_REALTIME, &mut timespec); + Sys::clock_gettime( + time::constants::CLOCK_REALTIME, + Out::from_mut(&mut timespec), + ); } let tid = (timespec.tv_nsec >> 16) as u16; @@ -149,7 +155,12 @@ pub fn lookup_addr(addr: in_addr) -> Result>, c_int> { ); let mut timespec = timespec::default(); - unsafe { Sys::clock_gettime(time::constants::CLOCK_REALTIME, &mut timespec) }; + unsafe { + Sys::clock_gettime( + time::constants::CLOCK_REALTIME, + Out::from_mut(&mut timespec), + ) + }; let tid = (timespec.tv_nsec >> 16) as u16; let packet = Dns { diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs index b7c7c7b633..74acc5ee1d 100644 --- a/src/header/stdio/mod.rs +++ b/src/header/stdio/mod.rs @@ -26,6 +26,7 @@ use crate::{ unistd, }, io::{self, BufRead, BufWriter, LineWriter, Read, Write}, + out::Out, platform::{self, types::*, Pal, Sys, WriteByte, ERRNO}, sync::Mutex, }; @@ -826,6 +827,7 @@ pub unsafe extern "C" fn getw(stream: *mut FILE) -> c_int { #[no_mangle] pub unsafe extern "C" fn pclose(stream: *mut FILE) -> c_int { + // TODO: rusty error handling? let pid = { let mut stream = (*stream).lock(); @@ -840,7 +842,7 @@ pub unsafe extern "C" fn pclose(stream: *mut FILE) -> c_int { fclose(stream); let mut wstatus = 0; - if Sys::waitpid(pid, &mut wstatus, 0).or_minus_one_errno() == -1 { + if Sys::waitpid(pid, Some(Out::from_mut(&mut wstatus)), 0).or_minus_one_errno() == -1 { return -1; } diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index 1da1a154fa..be8b4fca60 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -27,6 +27,7 @@ use crate::{ wchar::*, }, ld_so, + out::Out, platform::{self, types::*, Pal, Sys}, sync::Once, }; @@ -760,7 +761,7 @@ where fn get_nstime() -> u64 { unsafe { let mut ts = mem::MaybeUninit::uninit(); - Sys::clock_gettime(CLOCK_MONOTONIC, ts.as_mut_ptr()); + Sys::clock_gettime(CLOCK_MONOTONIC, Out::from_uninit_mut(&mut ts)); ts.assume_init().tv_nsec as u64 } } @@ -1523,6 +1524,7 @@ pub unsafe extern "C" fn strtoull( /// See . #[no_mangle] pub unsafe extern "C" fn system(command: *const c_char) -> c_int { + // TODO: rusty error handling? //TODO: share code with popen // handle shell detection on command == NULL @@ -1555,7 +1557,8 @@ pub unsafe extern "C" fn system(command: *const c_char) -> c_int { unreachable!(); } else if child_pid > 0 { let mut wstatus = 0; - if Sys::waitpid(child_pid, &mut wstatus, 0).or_minus_one_errno() == -1 { + if Sys::waitpid(child_pid, Some(Out::from_mut(&mut wstatus)), 0).or_minus_one_errno() == -1 + { return -1; } diff --git a/src/header/sys_resource/mod.rs b/src/header/sys_resource/mod.rs index bc1cc1167b..0d93354d43 100644 --- a/src/header/sys_resource/mod.rs +++ b/src/header/sys_resource/mod.rs @@ -4,6 +4,7 @@ use crate::{ error::ResultExt, header::sys_time::timeval, + out::Out, platform::{types::*, Pal, Sys}, }; @@ -84,6 +85,8 @@ pub unsafe extern "C" fn setpriority(which: c_int, who: id_t, nice: c_int) -> c_ #[no_mangle] pub unsafe extern "C" fn getrlimit(resource: c_int, rlp: *mut rlimit) -> c_int { + let rlp = Out::nonnull(rlp); + Sys::getrlimit(resource, rlp) .map(|()| 0) .or_minus_one_errno() @@ -98,7 +101,7 @@ pub unsafe extern "C" fn setrlimit(resource: c_int, rlp: *const rlimit) -> c_int #[no_mangle] pub unsafe extern "C" fn getrusage(who: c_int, r_usage: *mut rusage) -> c_int { - Sys::getrusage(who, &mut *r_usage) + Sys::getrusage(who, Out::nonnull(r_usage)) .map(|()| 0) .or_minus_one_errno() } diff --git a/src/header/sys_stat/mod.rs b/src/header/sys_stat/mod.rs index 2ff4cdfa90..dc4c656405 100644 --- a/src/header/sys_stat/mod.rs +++ b/src/header/sys_stat/mod.rs @@ -7,6 +7,7 @@ use crate::{ fcntl::{O_NOFOLLOW, O_PATH}, time::timespec, }, + out::Out, platform::{types::*, Pal, Sys}, }; @@ -83,6 +84,7 @@ pub extern "C" fn fchmod(fildes: c_int, mode: mode_t) -> c_int { #[no_mangle] pub unsafe extern "C" fn fstat(fildes: c_int, buf: *mut stat) -> c_int { + let buf = Out::nonnull(buf); Sys::fstat(fildes, buf).map(|()| 0).or_minus_one_errno() } @@ -93,6 +95,8 @@ pub unsafe extern "C" fn fstatat( buf: *mut stat, flags: c_int, ) -> c_int { + let path = CStr::from_nullable_ptr(path); + let buf = Out::nonnull(buf); Sys::fstatat(fildes, path, buf, flags) .map(|()| 0) .or_minus_one_errno() @@ -111,6 +115,8 @@ pub unsafe extern "C" fn futimens(fd: c_int, times: *const timespec) -> c_int { #[no_mangle] pub unsafe extern "C" fn lstat(path: *const c_char, buf: *mut stat) -> c_int { let path = CStr::from_ptr(path); + let buf = Out::nonnull(buf); + // TODO: Rustify let fd = Sys::open(path, O_PATH | O_NOFOLLOW, 0).or_minus_one_errno(); if fd < 0 { @@ -159,6 +165,8 @@ pub unsafe extern "C" fn mknodat( #[no_mangle] pub unsafe extern "C" fn stat(file: *const c_char, buf: *mut stat) -> c_int { let file = CStr::from_ptr(file); + let buf = Out::nonnull(buf); + // TODO: Rustify let fd = Sys::open(file, O_PATH, 0).or_minus_one_errno(); if fd < 0 { diff --git a/src/header/sys_statvfs/mod.rs b/src/header/sys_statvfs/mod.rs index 306e0436bf..e9087fbe2c 100644 --- a/src/header/sys_statvfs/mod.rs +++ b/src/header/sys_statvfs/mod.rs @@ -4,6 +4,7 @@ use crate::{ c_str::CStr, error::ResultExt, header::fcntl::O_PATH, + out::Out, platform::{types::*, Pal, Sys}, }; @@ -28,12 +29,14 @@ pub struct statvfs { #[no_mangle] pub unsafe extern "C" fn fstatvfs(fildes: c_int, buf: *mut statvfs) -> c_int { + let buf = Out::nonnull(buf); Sys::fstatvfs(fildes, buf).map(|()| 0).or_minus_one_errno() } #[no_mangle] pub unsafe extern "C" fn statvfs(file: *const c_char, buf: *mut statvfs) -> c_int { let file = CStr::from_ptr(file); + let buf = Out::nonnull(buf); // TODO: Rustify let fd = Sys::open(file, O_PATH, 0).or_minus_one_errno(); if fd < 0 { diff --git a/src/header/sys_time/mod.rs b/src/header/sys_time/mod.rs index 7999d0d0fe..7a54243efd 100644 --- a/src/header/sys_time/mod.rs +++ b/src/header/sys_time/mod.rs @@ -6,6 +6,7 @@ use crate::{ c_str::CStr, error::ResultExt, header::time::timespec, + out::Out, platform::{types::*, Pal, PalSignal, Sys}, }; use core::ptr::null; @@ -97,7 +98,9 @@ pub unsafe extern "C" fn getitimer(which: c_int, value: *mut itimerval) -> c_int #[deprecated] #[no_mangle] pub unsafe extern "C" fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> c_int { - Sys::gettimeofday(tp, tzp).map(|()| 0).or_minus_one_errno() + Sys::gettimeofday(Out::nonnull(tp), Out::nullable(tzp)) + .map(|()| 0) + .or_minus_one_errno() } // `select()` declared in `sys/select.h`, as specified in modern POSIX diff --git a/src/header/sys_wait/mod.rs b/src/header/sys_wait/mod.rs index e482bb3211..bb0fe62034 100644 --- a/src/header/sys_wait/mod.rs +++ b/src/header/sys_wait/mod.rs @@ -1,7 +1,7 @@ //! sys/wait.h implementation for Redox, following //! http://pubs.opengroup.org/onlinepubs/7908799/xsh/syswait.h.html -use crate::error::ResultExt; +use crate::{error::ResultExt, out::Out}; //use header::sys_resource::rusage; use crate::platform::{types::*, Pal, Sys}; @@ -48,5 +48,5 @@ pub unsafe extern "C" fn wait(stat_loc: *mut c_int) -> pid_t { #[no_mangle] pub unsafe extern "C" fn waitpid(pid: pid_t, stat_loc: *mut c_int, options: c_int) -> pid_t { - Sys::waitpid(pid, stat_loc, options).or_minus_one_errno() + Sys::waitpid(pid, Out::nullable(stat_loc), options).or_minus_one_errno() } diff --git a/src/header/time/mod.rs b/src/header/time/mod.rs index 7819112ac4..df476a073c 100644 --- a/src/header/time/mod.rs +++ b/src/header/time/mod.rs @@ -8,6 +8,7 @@ use crate::{ fs::File, header::{errno::EOVERFLOW, fcntl::O_RDONLY, stdlib::getenv, unistd::readlink}, io::Read, + out::Out, platform::{self, types::*, Pal, Sys}, sync::{Mutex, MutexGuard}, }; @@ -259,8 +260,8 @@ pub extern "C" fn clock_getcpuclockid(pid: pid_t, clock_id: *mut clockid_t) -> c /// See . #[no_mangle] -pub unsafe extern "C" fn clock_getres(clock_id: clockid_t, tp: *mut timespec) -> c_int { - Sys::clock_getres(clock_id, tp) +pub unsafe extern "C" fn clock_getres(clock_id: clockid_t, res: *mut timespec) -> c_int { + Sys::clock_getres(clock_id, Out::nullable(res)) .map(|()| 0) .or_minus_one_errno() } @@ -268,7 +269,7 @@ pub unsafe extern "C" fn clock_getres(clock_id: clockid_t, tp: *mut timespec) -> /// See . #[no_mangle] pub unsafe extern "C" fn clock_gettime(clock_id: clockid_t, tp: *mut timespec) -> c_int { - Sys::clock_gettime(clock_id, tp) + Sys::clock_gettime(clock_id, Out::nonnull(tp)) .map(|()| 0) .or_minus_one_errno() } @@ -449,7 +450,7 @@ pub unsafe extern "C" fn strftime( #[no_mangle] pub unsafe extern "C" fn time(tloc: *mut time_t) -> time_t { let mut ts = timespec::default(); - Sys::clock_gettime(CLOCK_REALTIME, &mut ts); + Sys::clock_gettime(CLOCK_REALTIME, Out::from_mut(&mut ts)); if !tloc.is_null() { *tloc = ts.tv_sec }; @@ -646,7 +647,7 @@ fn time_zone() -> Tz { fn now() -> NaiveDateTime { let mut now = timespec::default(); unsafe { - Sys::clock_gettime(CLOCK_REALTIME, &mut now); + Sys::clock_gettime(CLOCK_REALTIME, Out::from_mut(&mut now)); } NaiveDateTime::from_timestamp(now.tv_sec, now.tv_nsec as _) } diff --git a/src/header/unistd/mod.rs b/src/header/unistd/mod.rs index 204b407361..bde3b1c551 100644 --- a/src/header/unistd/mod.rs +++ b/src/header/unistd/mod.rs @@ -20,6 +20,7 @@ use crate::{ sys_ioctl, sys_resource, sys_time, sys_utsname, termios, time::timespec, }, + out::Out, platform::{self, types::*, Pal, Sys, ERRNO}, }; @@ -35,7 +36,7 @@ pub use crate::header::stdio::{ctermid, cuserid}; //pub use crate::header::fcntl::{faccessat, fchownat, fexecve, linkat, readlinkat, symlinkat, unlinkat}; use super::{ - errno::{E2BIG, ENOMEM}, + errno::{E2BIG, EINVAL, ENOMEM}, stdio::snprintf, }; @@ -460,7 +461,7 @@ pub unsafe extern "C" fn getcwd(mut buf: *mut c_char, mut size: size_t) -> *mut size = stack_buf.len(); } - let ret = match Sys::getcwd(buf, size) { + let ret = match Sys::getcwd(Out::from_raw_parts(buf.cast(), size)) { Ok(()) => buf, Err(Errno(errno)) => { ERRNO.set(errno); @@ -538,7 +539,17 @@ pub extern "C" fn getgid() -> gid_t { /// See . #[no_mangle] pub unsafe extern "C" fn getgroups(size: c_int, list: *mut gid_t) -> c_int { - Sys::getgroups(size, list).or_minus_one_errno() + (|| { + let size = usize::try_from(size) + // fails for negative size, but EINVAL required if size != 0 && size < actual size, + // where the actual number of entries in the group list is obviously nonnegative + .map_err(|_| Errno(EINVAL))?; + + let list = Out::from_raw_parts(list, size); + + Sys::getgroups(list) + })() + .or_minus_one_errno() } /// See . @@ -637,19 +648,25 @@ pub extern "C" fn getppid() -> pid_t { /// See . #[no_mangle] pub unsafe extern "C" fn getresgid(rgid: *mut gid_t, egid: *mut gid_t, sgid: *mut gid_t) -> c_int { - // TODO: Out write-only wrapper? - Sys::getresgid(rgid.as_mut(), egid.as_mut(), sgid.as_mut()) - .map(|()| 0) - .or_minus_one_errno() + Sys::getresgid( + Out::nullable(rgid), + Out::nullable(egid), + Out::nullable(sgid), + ) + .map(|()| 0) + .or_minus_one_errno() } /// See . #[no_mangle] pub unsafe extern "C" fn getresuid(ruid: *mut uid_t, euid: *mut uid_t, suid: *mut uid_t) -> c_int { - // TODO: Out write-only wrapper? - Sys::getresuid(ruid.as_mut(), euid.as_mut(), suid.as_mut()) - .map(|()| 0) - .or_minus_one_errno() + Sys::getresuid( + Out::nullable(ruid), + Out::nullable(euid), + Out::nullable(suid), + ) + .map(|()| 0) + .or_minus_one_errno() } /// See . @@ -770,7 +787,7 @@ pub unsafe extern "C" fn pipe(fildes: *mut c_int) -> c_int { /// See . #[no_mangle] pub unsafe extern "C" fn pipe2(fildes: *mut c_int, flags: c_int) -> c_int { - Sys::pipe2(slice::from_raw_parts_mut(fildes, 2), flags) + Sys::pipe2(Out::nonnull(fildes.cast::<[c_int; 2]>()), flags) .map(|()| 0) .or_minus_one_errno() } diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index 6ea71c3dfd..357644237d 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -25,6 +25,7 @@ use crate::{ unistd::F_OK, }, ld_so::dso::{resolve_sym, SymbolBinding}, + out::Out, platform::{ types::{c_int, c_uint, c_void}, Pal, Sys, @@ -88,9 +89,7 @@ impl MmapFile { fn open(path: CStr, oflag: c_int) -> core::result::Result { let fd = Sys::open(path, oflag, 0 /* mode */)?; let mut stat = crate::header::sys_stat::stat::default(); - unsafe { - Sys::fstat(fd, &mut stat)?; - } + Sys::fstat(fd, Out::from_mut(&mut stat))?; let size = stat.st_size as usize; let ptr = unsafe { diff --git a/src/lib.rs b/src/lib.rs index 2a35e41b97..b97bdfd71c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,7 @@ #![feature(pointer_is_aligned_to)] #![feature(ptr_as_uninit)] #![feature(slice_as_chunks)] +#![feature(slice_ptr_get)] #![feature(stmt_expr_attributes)] #![feature(strict_provenance)] #![feature(sync_unsafe_cell)] @@ -63,6 +64,7 @@ pub mod header; pub mod io; pub mod iter; pub mod ld_so; +pub mod out; pub mod platform; pub mod pthread; pub mod start; diff --git a/src/out.rs b/src/out.rs new file mode 100644 index 0000000000..4bf241b8ad --- /dev/null +++ b/src/out.rs @@ -0,0 +1,167 @@ +//! Wrapper for the "out pointer" pattern. +//! +//! This is functionally equivalent to `&Cell>` except the only allowed operation is +//! to write a `T`. Using `MaybeUninit` directly would not have been equally general; a +//! `&mut MaybeUninit` could never then be created from a `&mut T` and passed to safe code, +//! which can safely replace it with `MaybeUninit::uninit` and make the existence of `&mut T` UB. +//! +//! As for the "`&Cell<...>`", this is to be slightly weaker than Rust's normally strict +//! requirement that `&mut` references are never aliased, which can typically not be assumed when +//! getting pointers from C. + +use core::{cell::UnsafeCell, fmt, marker::PhantomData, mem::MaybeUninit, ptr::NonNull}; + +/// Wrapper for write-only "out pointers" that are safe to write to +// TODO: We may want to change this to &mut MaybeUninit, or have a generic parameter deciding +// whether it should be noalias or not +#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Out<'a, T: ?Sized> { + ptr: NonNull, + _marker: PhantomData<&'a UnsafeCell>, +} +impl<'a, T: ?Sized> Out<'a, T> { + /// # Safety + /// + /// - pointer must either be NULL, or be valid for the duration of lifetime `'a` + #[inline] + pub unsafe fn nullable(ptr: *mut T) -> Option { + Some(Self { + ptr: NonNull::new(ptr)?, + _marker: PhantomData, + }) + } + /// # Safety + /// + /// - pointer must be valid for the duration of lifetime `'a` + #[inline] + pub unsafe fn nonnull(ptr: *mut T) -> Self { + if cfg!(debug_assertions) { + assert!(!ptr.is_null()); + } + Self { + ptr: NonNull::new_unchecked(ptr), + _marker: PhantomData, + } + } + #[inline] + pub fn from_mut(r: &'a mut T) -> Self { + // SAFETY: + // + // - `r` will obviously have the same lifetime as Self + // - a Rust reference is obviously valid as a pointer, and the lifetime is tied to that of + // this struct + unsafe { Self::nonnull(r) } + } + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut T { + self.ptr.as_ptr() + } +} +impl<'a, T> Out<'a, T> { + #[inline] + pub fn from_uninit_mut(r: &'a mut MaybeUninit) -> Self { + // SAFETY: + // + // Same as for from_mut. It's fine if *r is uninitialized, as this wrapper only allows + // writes. + unsafe { Self::nonnull(r.as_mut_ptr()) } + } + #[inline] + pub fn write(&mut self, t: T) { + unsafe { + self.ptr.as_ptr().write(t); + } + } +} +impl<'a, T> Out<'a, [T]> { + /// # Safety + /// + /// If `len > 0`, `ptr` be valid for `len` elements of `T`, during lifetime `'a`. + pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self { + // Empty slices must be non-NULL in Rust, but C typically does not force this for + // pointer-length pairs. + let ptr = if len == 0 { + core::ptr::dangling_mut::() + } else { + ptr + }; + Self::nonnull(core::slice::from_raw_parts_mut(ptr, len)) + } + pub fn len(&self) -> usize { + self.ptr.as_ptr().len() + } + // TODO: Maybe strengthen lifetimes? + #[inline] + pub fn split_at_checked<'b>(&'b mut self, n: usize) -> Option<[Out<'b, [T]>; 2]> { + let l = self.ptr.len(); + if n > l { + return None; + } + Some([ + Out { + ptr: unsafe { + NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + self.ptr.as_mut_ptr(), + n, + )) + }, + _marker: PhantomData, + }, + Out { + ptr: unsafe { + NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + self.ptr.as_mut_ptr().add(n), + l - n, + )) + }, + _marker: PhantomData, + }, + ]) + } + #[inline] + pub fn copy_from_slice(&mut self, src: &[T]) + where + T: Copy, + { + assert_eq!( + self.ptr.len(), + src.len(), + "Out::copy_from_slice size mismatch" + ); + unsafe { + // SAFETY: + // + // - we have already know from the existence of self that the slice is a valid writable + // pointer + // - src is similarly also a valid readable pointer of the same type + // - because of `T: Copy`, it is valid to copy bytes directly + // - although self.ptr may alias, src must not alias with any writable pointer, and the + // Copy bound ensures T cannot have interior mutability since `UnsafeCell: !Copy` + self.ptr + .as_mut_ptr() + .copy_from_nonoverlapping(src.as_ptr(), src.len()); + } + } +} +// TODO: different trait? +impl Out<'_, [T]> { + pub fn zero(&mut self) { + let l = self.ptr.len(); + unsafe { + // SAFETY: + // - already know the pointer is valid up to its length + // - the Plain trait ensures zero is a valid bit pattern + self.ptr.as_mut_ptr().write_bytes(0, l) + } + } +} +impl fmt::Pointer for Out<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:p}", self.ptr) + } +} +impl fmt::Debug for Out<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[Out: {:p}]", self.ptr) + } +} diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 1a2c538e6a..6bf219543e 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -1,4 +1,4 @@ -use crate::{header::errno::EOPNOTSUPP, io::Write}; +use crate::{header::errno::EOPNOTSUPP, io::Write, out::Out}; use core::{arch::asm, ptr}; use super::{types::*, Pal, ERRNO}; @@ -109,12 +109,19 @@ impl Pal for Sys { .map(|_| ()) } - unsafe fn clock_getres(clk_id: clockid_t, tp: *mut timespec) -> Result<()> { - e_raw(syscall!(CLOCK_GETRES, clk_id, tp)).map(|_| ()) + fn clock_getres(clk_id: clockid_t, res: Option>) -> Result<()> { + e_raw(unsafe { + syscall!( + CLOCK_GETRES, + clk_id, + res.map_or(core::ptr::null_mut(), |mut p| p.as_mut_ptr()) + ) + }) + .map(|_| ()) } - unsafe fn clock_gettime(clk_id: clockid_t, tp: *mut timespec) -> Result<()> { - e_raw(syscall!(CLOCK_GETTIME, clk_id, tp)).map(|_| ()) + fn clock_gettime(clk_id: clockid_t, mut tp: Out) -> Result<()> { + e_raw(unsafe { syscall!(CLOCK_GETTIME, clk_id, tp.as_mut_ptr()) }).map(|_| ()) } unsafe fn clock_settime(clk_id: clockid_t, tp: *const timespec) -> Result<()> { @@ -176,42 +183,59 @@ impl Pal for Sys { e_raw(unsafe { syscall!(FLOCK, fd, operation) }).map(|_| ()) } - unsafe fn fstat(fildes: c_int, buf: *mut stat) -> Result<()> { + fn fstat(fildes: c_int, mut buf: Out) -> Result<()> { let empty = b"\0"; let empty_ptr = empty.as_ptr() as *const c_char; - e_raw(unsafe { syscall!(NEWFSTATAT, fildes, empty_ptr, buf, AT_EMPTY_PATH) }).map(|_| ()) + e_raw(unsafe { + syscall!( + NEWFSTATAT, + fildes, + empty_ptr, + buf.as_mut_ptr(), + AT_EMPTY_PATH + ) + }) + .map(|_| ()) } - unsafe fn fstatat( - fildes: c_int, - path: *const c_char, - buf: *mut stat, - flags: c_int, - ) -> Result<()> { - e_raw(unsafe { syscall!(NEWFSTATAT, fildes, path, buf, flags) }).map(|_| ()) + fn fstatat(fildes: c_int, path: Option, mut buf: Out, flags: c_int) -> Result<()> { + e_raw(unsafe { + syscall!( + NEWFSTATAT, + fildes, + path.map_or(core::ptr::null(), |s| s.as_ptr()), + buf.as_mut_ptr(), + flags + ) + }) + .map(|_| ()) } - unsafe fn fstatvfs(fildes: c_int, buf: *mut statvfs) -> Result<()> { + fn fstatvfs(fildes: c_int, mut buf: Out) -> Result<()> { + let buf = buf.as_mut_ptr(); + let mut kbuf = linux_statfs::default(); let kbuf_ptr = &mut kbuf as *mut linux_statfs; - e_raw(syscall!(FSTATFS, fildes, kbuf_ptr))?; + e_raw(unsafe { syscall!(FSTATFS, fildes, kbuf_ptr) })?; if !buf.is_null() { - (*buf).f_bsize = kbuf.f_bsize as c_ulong; - (*buf).f_frsize = if kbuf.f_frsize != 0 { - kbuf.f_frsize - } else { - kbuf.f_bsize - } as c_ulong; - (*buf).f_blocks = kbuf.f_blocks; - (*buf).f_bfree = kbuf.f_bfree; - (*buf).f_bavail = kbuf.f_bavail; - (*buf).f_files = kbuf.f_files; - (*buf).f_ffree = kbuf.f_ffree; - (*buf).f_favail = kbuf.f_ffree; - (*buf).f_fsid = kbuf.f_fsid as c_ulong; - (*buf).f_flag = kbuf.f_flags as c_ulong; - (*buf).f_namemax = kbuf.f_namelen as c_ulong; + unsafe { + (*buf).f_bsize = kbuf.f_bsize as c_ulong; + (*buf).f_frsize = if kbuf.f_frsize != 0 { + kbuf.f_frsize + } else { + kbuf.f_bsize + } as c_ulong; + (*buf).f_blocks = kbuf.f_blocks; + (*buf).f_bfree = kbuf.f_bfree; + (*buf).f_bavail = kbuf.f_bavail; + (*buf).f_files = kbuf.f_files; + (*buf).f_ffree = kbuf.f_ffree; + (*buf).f_favail = kbuf.f_ffree; + (*buf).f_fsid = kbuf.f_fsid as c_ulong; + (*buf).f_flag = kbuf.f_flags as c_ulong; + (*buf).f_namemax = kbuf.f_namelen as c_ulong; + } } Ok(()) } @@ -268,8 +292,14 @@ impl Pal for Sys { e_raw(unsafe { syscall!(UTIMENSAT, AT_FDCWD, path.as_ptr(), times, 0) }).map(|_| ()) } - unsafe fn getcwd(buf: *mut c_char, size: size_t) -> Result<()> { - e_raw(unsafe { syscall!(GETCWD, buf, size) })?; + fn getcwd(mut buf: Out<[u8]>) -> Result<()> { + e_raw(unsafe { + syscall!( + GETCWD, + buf.as_mut_ptr().as_mut_ptr(), + buf.as_mut_ptr().len() + ) + })?; Ok(()) } @@ -300,8 +330,14 @@ impl Pal for Sys { unsafe { syscall!(GETGID) as gid_t } } - unsafe fn getgroups(size: c_int, list: *mut gid_t) -> Result { - Ok(e_raw(unsafe { syscall!(GETGROUPS, size, list) })? as c_int) + fn getgroups(mut list: Out<[gid_t]>) -> Result { + Ok(e_raw(unsafe { + syscall!( + GETGROUPS, + list.len() as c_int, + list.as_mut_ptr().as_mut_ptr() + ) + })? as c_int) } fn getpagesize() -> usize { @@ -330,36 +366,36 @@ impl Pal for Sys { e_raw(unsafe { syscall!(GETRANDOM, buf.as_mut_ptr(), buf.len(), flags) }) } - unsafe fn getrlimit(resource: c_int, rlim: *mut rlimit) -> Result<()> { - e_raw(syscall!(GETRLIMIT, resource, rlim)).map(|_| ()) + fn getrlimit(resource: c_int, mut rlim: Out) -> Result<()> { + e_raw(unsafe { syscall!(GETRLIMIT, resource, rlim.as_mut_ptr()) }).map(|_| ()) } fn getresgid( - rgid: Option<&mut gid_t>, - egid: Option<&mut gid_t>, - sgid: Option<&mut gid_t>, + rgid: Option>, + egid: Option>, + sgid: Option>, ) -> Result<()> { unsafe { e_raw(syscall!( GETRESGID, - rgid.map_or(0, |r| r as *const _ as usize), - egid.map_or(0, |r| r as *const _ as usize), - sgid.map_or(0, |r| r as *const _ as usize) + rgid.map_or(0, |mut r| r.as_mut_ptr() as usize), + egid.map_or(0, |mut r| r.as_mut_ptr() as usize), + sgid.map_or(0, |mut r| r.as_mut_ptr() as usize) )) .map(|_| ()) } } fn getresuid( - ruid: Option<&mut uid_t>, - euid: Option<&mut uid_t>, - suid: Option<&mut uid_t>, + ruid: Option>, + euid: Option>, + suid: Option>, ) -> Result<()> { unsafe { e_raw(syscall!( GETRESUID, - ruid.map_or(0, |r| r as *const _ as usize), - euid.map_or(0, |r| r as *const _ as usize), - suid.map_or(0, |r| r as *const _ as usize) + ruid.map_or(0, |mut r| r.as_mut_ptr() as usize), + euid.map_or(0, |mut r| r.as_mut_ptr() as usize), + suid.map_or(0, |mut r| r.as_mut_ptr() as usize) )) .map(|_| ()) } @@ -369,8 +405,8 @@ impl Pal for Sys { e_raw(syscall!(SETRLIMIT, resource, rlimit)).map(|_| ()) } - fn getrusage(who: c_int, r_usage: &mut rusage) -> Result<()> { - e_raw(unsafe { syscall!(GETRUSAGE, who, r_usage as *mut rusage) })?; + fn getrusage(who: c_int, mut r_usage: Out) -> Result<()> { + e_raw(unsafe { syscall!(GETRUSAGE, who, r_usage.as_mut_ptr()) })?; Ok(()) } @@ -383,8 +419,15 @@ impl Pal for Sys { unsafe { syscall!(GETTID) as pid_t } } - unsafe fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> Result<()> { - e_raw(unsafe { syscall!(GETTIMEOFDAY, tp, tzp) }).map(|_| ()) + fn gettimeofday(mut tp: Out, tzp: Option>) -> Result<()> { + e_raw(unsafe { + syscall!( + GETTIMEOFDAY, + tp.as_mut_ptr(), + tzp.map_or(0, |mut p| p.as_mut_ptr() as usize) + ) + }) + .map(|_| ()) } fn getuid() -> uid_t { @@ -498,7 +541,7 @@ impl Pal for Sys { .map(|fd| fd as c_int) } - fn pipe2(fildes: &mut [c_int], flags: c_int) -> Result<()> { + fn pipe2(mut fildes: Out<[c_int; 2]>, flags: c_int) -> Result<()> { e_raw(unsafe { syscall!(PIPE2, fildes.as_mut_ptr(), flags) }).map(|_| ()) } @@ -647,15 +690,24 @@ impl Pal for Sys { } unsafe fn uname(utsname: *mut utsname) -> Result<()> { - e_raw(syscall!(UNAME, utsname, 0)).map(|_| ()) + e_raw(unsafe { syscall!(UNAME, utsname, 0) }).map(|_| ()) } fn unlink(path: CStr) -> Result<()> { e_raw(unsafe { syscall!(UNLINKAT, AT_FDCWD, path.as_ptr(), 0) }).map(|_| ()) } - unsafe fn waitpid(pid: pid_t, stat_loc: *mut c_int, options: c_int) -> Result { - e_raw(unsafe { syscall!(WAIT4, pid, stat_loc, options, 0) }).map(|p| p as pid_t) + fn waitpid(pid: pid_t, stat_loc: Option>, options: c_int) -> Result { + e_raw(unsafe { + syscall!( + WAIT4, + pid, + stat_loc.map_or(core::ptr::null_mut(), |mut o| o.as_mut_ptr()), + options, + 0 + ) + }) + .map(|p| p as pid_t) } fn write(fildes: c_int, buf: &[u8]) -> Result { diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs index f0717374fc..de64a37a8d 100644 --- a/src/platform/pal/mod.rs +++ b/src/platform/pal/mod.rs @@ -10,6 +10,7 @@ use crate::{ sys_utsname::utsname, time::timespec, }, + out::Out, pthread, }; @@ -39,9 +40,10 @@ pub trait Pal { fn chown(path: CStr, owner: uid_t, group: gid_t) -> Result<()>; - unsafe fn clock_getres(clk_id: clockid_t, tp: *mut timespec) -> Result<()>; + fn clock_getres(clk_id: clockid_t, tp: Option>) -> Result<()>; - unsafe fn clock_gettime(clk_id: clockid_t, tp: *mut timespec) -> Result<()>; + // TODO: maybe remove tp and change signature to -> Result? + fn clock_gettime(clk_id: clockid_t, tp: Out) -> Result<()>; unsafe fn clock_settime(clk_id: clockid_t, tp: *const timespec) -> Result<()>; @@ -72,16 +74,11 @@ pub trait Pal { fn flock(fd: c_int, operation: c_int) -> Result<()>; - unsafe fn fstat(fildes: c_int, buf: *mut stat) -> Result<()>; + fn fstat(fildes: c_int, buf: Out) -> Result<()>; - unsafe fn fstatat( - fildes: c_int, - path: *const c_char, - buf: *mut stat, - flags: c_int, - ) -> Result<()>; + fn fstatat(fildes: c_int, path: Option, buf: Out, flags: c_int) -> Result<()>; - unsafe fn fstatvfs(fildes: c_int, buf: *mut statvfs) -> Result<()>; + fn fstatvfs(fildes: c_int, buf: Out) -> Result<()>; fn fcntl(fildes: c_int, cmd: c_int, arg: c_ulonglong) -> Result; @@ -100,7 +97,7 @@ pub trait Pal { unsafe fn utimens(path: CStr, times: *const timespec) -> Result<()>; - unsafe fn getcwd(buf: *mut c_char, size: size_t) -> Result<()>; + fn getcwd(buf: Out<[u8]>) -> Result<()>; fn getdents(fd: c_int, buf: &mut [u8], opaque_offset: u64) -> Result; fn dir_seek(fd: c_int, opaque_offset: u64) -> Result<()>; @@ -119,7 +116,7 @@ pub trait Pal { // Always successful fn getgid() -> gid_t; - unsafe fn getgroups(size: c_int, list: *mut gid_t) -> Result; + fn getgroups(list: Out<[gid_t]>) -> Result; /* Note that this is distinct from the legacy POSIX function * getpagesize(), which returns a c_int. On some Linux platforms, @@ -139,29 +136,29 @@ pub trait Pal { fn getrandom(buf: &mut [u8], flags: c_uint) -> Result; fn getresgid( - rgid: Option<&mut gid_t>, - egid: Option<&mut gid_t>, - sgid: Option<&mut gid_t>, + rgid: Option>, + egid: Option>, + sgid: Option>, ) -> Result<()>; fn getresuid( - ruid: Option<&mut uid_t>, - euid: Option<&mut uid_t>, - suid: Option<&mut uid_t>, + ruid: Option>, + euid: Option>, + suid: Option>, ) -> Result<()>; - unsafe fn getrlimit(resource: c_int, rlim: *mut rlimit) -> Result<()>; + fn getrlimit(resource: c_int, rlim: Out) -> Result<()>; unsafe fn setrlimit(resource: c_int, rlim: *const rlimit) -> Result<()>; - fn getrusage(who: c_int, r_usage: &mut rusage) -> Result<()>; + fn getrusage(who: c_int, r_usage: Out) -> Result<()>; fn getsid(pid: pid_t) -> Result; // Always successful fn gettid() -> pid_t; - unsafe fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> Result<()>; + fn gettimeofday(tp: Out, tzp: Option>) -> Result<()>; fn getuid() -> uid_t; @@ -216,7 +213,7 @@ pub trait Pal { fn open(path: CStr, oflag: c_int, mode: mode_t) -> Result; - fn pipe2(fildes: &mut [c_int], flags: c_int) -> Result<()>; + fn pipe2(fildes: Out<[c_int; 2]>, flags: c_int) -> Result<()>; unsafe fn rlct_clone(stack: *mut usize) -> Result; unsafe fn rlct_kill(os_tid: pthread::OsTid, signal: usize) -> Result<()>; @@ -259,7 +256,7 @@ pub trait Pal { fn unlink(path: CStr) -> Result<()>; - unsafe fn waitpid(pid: pid_t, stat_loc: *mut c_int, options: c_int) -> Result; + fn waitpid(pid: pid_t, stat_loc: Option>, options: c_int) -> Result; fn write(fildes: c_int, buf: &[u8]) -> Result; fn pwrite(fildes: c_int, buf: &[u8], offset: off_t) -> Result; diff --git a/src/platform/redox/extra.rs b/src/platform/redox/extra.rs index 5f099750be..3115e1e91f 100644 --- a/src/platform/redox/extra.rs +++ b/src/platform/redox/extra.rs @@ -19,16 +19,13 @@ pub unsafe extern "C" fn redox_fpath(fd: c_int, buf: *mut c_void, count: size_t) .or_minus_one_errno() } -pub fn pipe2(fds: &mut [c_int], flags: usize) -> syscall::error::Result<()> { - let fds = - <&mut [c_int; 2]>::try_from(fds).expect("expected Pal pipe2 to have validated pipe2 array"); - +pub fn pipe2(flags: usize) -> syscall::error::Result<[c_int; 2]> { let mut read_fd = FdGuard::new(syscall::open("/scheme/pipe", flags)?); let mut write_fd = FdGuard::new(syscall::dup(*read_fd, b"write")?); syscall::fcntl(*write_fd, F_SETFL, flags)?; syscall::fcntl(*write_fd, F_SETFD, flags)?; - *fds = [ + let fds = [ c_int::try_from(*read_fd).map_err(|_| Error::new(EMFILE))?, c_int::try_from(*write_fd).map_err(|_| Error::new(EMFILE))?, ]; @@ -36,5 +33,5 @@ pub fn pipe2(fds: &mut [c_int], flags: usize) -> syscall::error::Result<()> { read_fd.take(); write_fd.take(); - Ok(()) + Ok(fds) } diff --git a/src/platform/redox/libredox.rs b/src/platform/redox/libredox.rs index 2ae5ca843f..56b2bdd72a 100644 --- a/src/platform/redox/libredox.rs +++ b/src/platform/redox/libredox.rs @@ -14,6 +14,7 @@ use crate::{ sys_uio::iovec, time::timespec, }, + out::Out, platform::{types::*, PalSignal}, }; @@ -111,11 +112,13 @@ pub unsafe fn futimens(fd: usize, times: *const timespec) -> syscall::Result<()> syscall::futimens(fd as usize, ×)?; Ok(()) } -pub unsafe fn clock_gettime(clock: usize, tp: *mut timespec) -> syscall::Result<()> { - let mut redox_tp = syscall::TimeSpec::from(&*tp); +pub fn clock_gettime(clock: usize, mut tp: Out) -> syscall::Result<()> { + let mut redox_tp = syscall::TimeSpec::default(); syscall::clock_gettime(clock as usize, &mut redox_tp)?; - (*tp).tv_sec = redox_tp.tv_sec as time_t; - (*tp).tv_nsec = redox_tp.tv_nsec as c_long; + tp.write(timespec { + tv_sec: redox_tp.tv_sec as time_t, + tv_nsec: redox_tp.tv_nsec as c_long, + }); Ok(()) } @@ -331,7 +334,7 @@ pub unsafe extern "C" fn redox_munmap_v1(addr: *mut (), unaligned_len: usize) -> #[no_mangle] pub unsafe extern "C" fn redox_clock_gettime_v1(clock: usize, ts: *mut timespec) -> RawResult { - Error::mux(clock_gettime(clock, ts).map(|()| 0)) + Error::mux(clock_gettime(clock, Out::nonnull(ts)).map(|()| 0)) } #[no_mangle] diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 01d4f9f576..9d915a6a54 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -25,7 +25,8 @@ use crate::{ EBADF, EBADFD, EBADR, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT, ENOMEM, ENOSYS, EOPNOTSUPP, EPERM, ERANGE, }, - fcntl, limits, + fcntl::{self, AT_FDCWD, O_RDONLY}, + limits, sys_mman::{MAP_ANONYMOUS, MAP_FAILED, PROT_READ, PROT_WRITE}, sys_random, sys_resource::{rlimit, rusage, RLIM_INFINITY}, @@ -38,6 +39,7 @@ use crate::{ unistd::{F_OK, R_OK, W_OK, X_OK}, }, io::{self, prelude::*, BufReader}, + out::Out, sync::rwlock::RwLock, }; @@ -178,13 +180,16 @@ impl Pal for Sys { Self::fchown(*file, owner, group) } - unsafe fn clock_getres(clk_id: clockid_t, tp: *mut timespec) -> Result<()> { + fn clock_getres(clk_id: clockid_t, res: Option>) -> Result<()> { // TODO - eprintln!("relibc clock_getres({}, {:p}): not implemented", clk_id, tp); + eprintln!( + "relibc clock_getres({}, {:?}): not implemented", + clk_id, res + ); Err(Errno(ENOSYS)) } - unsafe fn clock_gettime(clk_id: clockid_t, tp: *mut timespec) -> Result<()> { + fn clock_gettime(clk_id: clockid_t, tp: Out) -> Result<()> { libredox::clock_gettime(clk_id as usize, tp)?; Ok(()) } @@ -281,26 +286,25 @@ impl Pal for Sys { Ok(clone::fork_impl(&redox_rt::proc::ForkArgs::Managed)? as pid_t) } - unsafe fn fstat(fildes: c_int, buf: *mut stat) -> Result<()> { - libredox::fstat(fildes as usize, buf)?; + fn fstat(fildes: c_int, mut buf: Out) -> Result<()> { + unsafe { + libredox::fstat(fildes as usize, buf.as_mut_ptr())?; + } Ok(()) } - unsafe fn fstatat( - dirfd: c_int, - path: *const c_char, - buf: *mut stat, - flags: c_int, - ) -> Result<()> { - let path = CStr::from_nullable_ptr(path) + fn fstatat(dirfd: c_int, path: Option, buf: Out, flags: c_int) -> Result<()> { + let path = path .and_then(|cs| str::from_utf8(cs.to_bytes()).ok()) .ok_or(Errno(ENOENT))?; let file = cap_path_at(dirfd, path, flags, 0)?; Sys::fstat(*file, buf) } - unsafe fn fstatvfs(fildes: c_int, buf: *mut statvfs) -> Result<()> { - libredox::fstatvfs(fildes as usize, buf)?; + fn fstatvfs(fildes: c_int, mut buf: Out) -> Result<()> { + unsafe { + libredox::fstatvfs(fildes as usize, buf.as_mut_ptr())?; + } Ok(()) } @@ -338,15 +342,8 @@ impl Pal for Sys { Self::futimens(*file, times) } - unsafe fn getcwd(buf: *mut c_char, size: size_t) -> Result<()> { - // TODO: Not using MaybeUninit seems a little unsafe - - let buf_slice = unsafe { slice::from_raw_parts_mut(buf as *mut u8, size as usize) }; - if buf_slice.is_empty() { - return Err(Errno(EINVAL)); - } - - path::getcwd(buf_slice).ok_or(Errno(ERANGE))?; + fn getcwd(buf: Out<[u8]>) -> Result<()> { + path::getcwd(buf).ok_or(Errno(ERANGE))?; Ok(()) } @@ -438,9 +435,13 @@ impl Pal for Sys { redox_rt::sys::posix_getresugid().rgid as gid_t } - unsafe fn getgroups(size: c_int, list: *mut gid_t) -> Result { + fn getgroups(list: Out<[gid_t]>) -> Result { // TODO - eprintln!("relibc getgroups({}, {:p}): not implemented", size, list); + eprintln!( + "relibc getgroups({}, {:p}): not implemented", + list.len(), + list + ); Err(Errno(ENOSYS)) } @@ -485,54 +486,54 @@ impl Pal for Sys { } fn getresgid( - rgid_out: Option<&mut gid_t>, - egid_out: Option<&mut gid_t>, - sgid_out: Option<&mut gid_t>, + rgid_out: Option>, + egid_out: Option>, + sgid_out: Option>, ) -> Result<()> { let Resugid { rgid, egid, sgid, .. } = redox_rt::sys::posix_getresugid(); - if let Some(rgid_out) = rgid_out { - *rgid_out = rgid as _; + if let Some(mut rgid_out) = rgid_out { + rgid_out.write(rgid as _); } - if let Some(egid_out) = egid_out { - *egid_out = egid as _; + if let Some(mut egid_out) = egid_out { + egid_out.write(egid as _); } - if let Some(sgid_out) = sgid_out { - *sgid_out = sgid as _; + if let Some(mut sgid_out) = sgid_out { + sgid_out.write(sgid as _); } Ok(()) } fn getresuid( - ruid_out: Option<&mut uid_t>, - euid_out: Option<&mut uid_t>, - suid_out: Option<&mut uid_t>, + ruid_out: Option>, + euid_out: Option>, + suid_out: Option>, ) -> Result<()> { let Resugid { ruid, euid, suid, .. } = redox_rt::sys::posix_getresugid(); - if let Some(ruid_out) = ruid_out { - *ruid_out = ruid as _; + if let Some(mut ruid_out) = ruid_out { + ruid_out.write(ruid as _); } - if let Some(euid_out) = euid_out { - *euid_out = euid as _; + if let Some(mut euid_out) = euid_out { + euid_out.write(euid as _); } - if let Some(suid_out) = suid_out { - *suid_out = suid as _; + if let Some(mut suid_out) = suid_out { + suid_out.write(suid as _); } Ok(()) } - unsafe fn getrlimit(resource: c_int, rlim: *mut rlimit) -> Result<()> { + fn getrlimit(resource: c_int, mut rlim: Out) -> Result<()> { //TODO eprintln!( "relibc getrlimit({}, {:p}): not implemented", resource, rlim ); - if !rlim.is_null() { - (*rlim).rlim_cur = RLIM_INFINITY; - (*rlim).rlim_max = RLIM_INFINITY; - } + rlim.write(rlimit { + rlim_cur: RLIM_INFINITY, + rlim_max: RLIM_INFINITY, + }); Ok(()) } @@ -545,7 +546,7 @@ impl Pal for Sys { Err(Errno(EPERM)) } - fn getrusage(who: c_int, r_usage: &mut rusage) -> Result<()> { + fn getrusage(who: c_int, r_usage: Out) -> Result<()> { //TODO eprintln!("relibc getrusage({}, {:p}): not implemented", who, r_usage); Ok(()) @@ -566,16 +567,20 @@ impl Pal for Sys { .unwrap() } - unsafe fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> Result<()> { + fn gettimeofday(mut tp: Out, tzp: Option>) -> Result<()> { let mut redox_tp = redox_timespec::default(); syscall::clock_gettime(syscall::CLOCK_REALTIME, &mut redox_tp)?; unsafe { - (*tp).tv_sec = redox_tp.tv_sec as time_t; - (*tp).tv_usec = (redox_tp.tv_nsec / 1000) as suseconds_t; + tp.write(timeval { + tv_sec: redox_tp.tv_sec as time_t, + tv_usec: (redox_tp.tv_nsec / 1000) as suseconds_t, + }); - if !tzp.is_null() { - (*tzp).tz_minuteswest = 0; - (*tzp).tz_dsttime = 0; + if let Some(mut tzp) = tzp { + tzp.write(timezone { + tz_minuteswest: 0, + tz_dsttime: 0, + }); } } Ok(()) @@ -791,8 +796,8 @@ impl Pal for Sys { Ok(libredox::open(path, oflag, effective_mode)? as c_int) } - fn pipe2(fds: &mut [c_int], flags: c_int) -> Result<()> { - extra::pipe2(fds, flags as usize)?; + fn pipe2(mut fds: Out<[c_int; 2]>, flags: c_int) -> Result<()> { + fds.write(extra::pipe2(flags as usize)?); Ok(()) } @@ -1048,7 +1053,7 @@ impl Pal for Sys { Ok(()) } - unsafe fn waitpid(mut pid: pid_t, stat_loc: *mut c_int, options: c_int) -> Result { + fn waitpid(mut pid: pid_t, stat_loc: Option>, options: c_int) -> Result { let mut res = None; let mut status = 0; @@ -1102,11 +1107,10 @@ impl Pal for Sys { }); // If stat_loc is non-null, set that and the return - unsafe { - if !stat_loc.is_null() { - *stat_loc = status as c_int; - } + if let Some(mut stat_loc) = stat_loc { + stat_loc.write(status as c_int); } + Ok(res? as pid_t) } diff --git a/src/platform/redox/path.rs b/src/platform/redox/path.rs index 3f7b4ca437..7942fb2db6 100644 --- a/src/platform/redox/path.rs +++ b/src/platform/redox/path.rs @@ -14,6 +14,7 @@ use crate::{ error::Errno, fs::File, header::{fcntl, limits}, + out::Out, sync::Mutex, }; @@ -44,19 +45,15 @@ pub fn chdir(path: &str) -> Result<()> { } // getcwd is similarly both thread-safe and signal-safe. -// TODO: MaybeUninit -pub fn getcwd(buf: &mut [u8]) -> Option { +pub fn getcwd(mut buf: Out<[u8]>) -> Option { let _siglock = tmp_disable_signals(); let cwd_guard = CWD.lock(); let cwd = cwd_guard.as_deref().unwrap_or("").as_bytes(); - // But is already checked not to be empty. - if buf.len() - 1 < cwd.len() { - return None; - } + let [mut before, mut after] = buf.split_at_checked(cwd.len())?; - buf[..cwd.len()].copy_from_slice(&cwd); - buf[cwd.len()..].fill(0_u8); + before.copy_from_slice(&cwd); + after.zero(); Some(cwd.len()) } @@ -238,7 +235,7 @@ pub fn cap_path_at( let path = if dirfd == fcntl::AT_FDCWD { // The special constant AT_FDCWD indicates that we should use the cwd. let mut buf = [0; limits::PATH_MAX]; - let len = getcwd(&mut buf).ok_or(Errno(ENAMETOOLONG))?; + let len = getcwd(Out::from_mut(&mut buf)).ok_or(Errno(ENAMETOOLONG))?; // SAFETY: Redox's cwd is stored as a str. let cwd = unsafe { str::from_utf8_unchecked(&buf[..len]) }; diff --git a/src/sync/mod.rs b/src/sync/mod.rs index 6b22256386..dc913e5131 100644 --- a/src/sync/mod.rs +++ b/src/sync/mod.rs @@ -26,6 +26,7 @@ use crate::{ errno::{EAGAIN, ETIMEDOUT}, time::timespec, }, + out::Out, platform::{types::*, Pal, Sys}, }; use core::{ @@ -140,7 +141,10 @@ pub fn rttime() -> timespec { let mut time = MaybeUninit::uninit(); // TODO: Handle error - Sys::clock_gettime(crate::header::time::CLOCK_REALTIME, time.as_mut_ptr()); + Sys::clock_gettime( + crate::header::time::CLOCK_REALTIME, + Out::from_uninit_mut(&mut time), + ); time.assume_init() }