//! Convert values to [`ArgReg`] and from [`RetReg`]. //! //! System call arguments and return values are all communicated with inline //! asm and FFI as `*mut Opaque`. To protect these raw pointers from escaping //! or being accidentally misused as they travel through the code, we wrap them //! in [`ArgReg`] and [`RetReg`] structs. This file provides `From` //! implementations and explicit conversion functions for converting values //! into and out of these wrapper structs. //! //! # Safety //! //! Some of this code is `unsafe` in order to work with raw file descriptors, //! and some is `unsafe` to interpret the values in a `RetReg`. #![allow(unsafe_code)]
/// Pass the "low" half of the endian-specific memory encoding of a `u64`, for /// 32-bit architectures. #[cfg(target_pointer_width = "32")] #[inline] pub(super) fn lo<'a, Num: ArgNumber>(x: u64) -> ArgReg<'a, Num> { #[cfg(target_endian = "little")] let x = x >> 32; #[cfg(target_endian = "big")] let x = x & 0xffff_ffff;
pass_usize(x as usize)
}
/// Pass the "high" half of the endian-specific memory encoding of a `u64`, for /// 32-bit architectures. #[cfg(target_pointer_width = "32")] #[inline] pub(super) fn hi<'a, Num: ArgNumber>(x: u64) -> ArgReg<'a, Num> { #[cfg(target_endian = "little")] let x = x & 0xffff_ffff; #[cfg(target_endian = "big")] let x = x >> 32;
pass_usize(x as usize)
}
/// Pass a zero, or null, argument. #[inline] pub(super) fn zero<'a, Num: ArgNumber>() -> ArgReg<'a, Num> {
raw_arg(null_mut())
}
/// Pass the `mem::size_of` of a type. #[inline] pub(super) fn size_of<'a, T: Sized, Num: ArgNumber>() -> ArgReg<'a, Num> {
pass_usize(core::mem::size_of::<T>())
}
/// Pass an arbitrary `usize` value. /// /// For passing pointers, use `void_star` or other functions which take a raw /// pointer instead of casting to `usize`, so that provenance is preserved. #[inline] pub(super) fn pass_usize<'a, Num: ArgNumber>(t: usize) -> ArgReg<'a, Num> {
raw_arg(t as *mut _)
}
impl<'a, Num: ArgNumber, T> From<*const T> for ArgReg<'a, Num> { #[inline] fn from(c: *const T) -> ArgReg<'a, Num> { let mut_ptr = c as *mut T;
raw_arg(mut_ptr.cast())
}
}
impl<'a, Num: ArgNumber> From<&'a CStr> for ArgReg<'a, Num> { #[inline] fn from(c: &'a CStr) -> Self { let mut_ptr = c.as_ptr() as *mut u8;
raw_arg(mut_ptr.cast())
}
}
impl<'a, Num: ArgNumber> From<Option<&'a CStr>> for ArgReg<'a, Num> { #[inline] fn from(t: Option<&'a CStr>) -> Self {
raw_arg(match t {
Some(s) => { let mut_ptr = s.as_ptr() as *mut u8;
mut_ptr.cast()
}
None => null_mut(),
})
}
}
/// Pass a borrowed file-descriptor argument. impl<'a, Num: ArgNumber> From<BorrowedFd<'a>> for ArgReg<'a, Num> { #[inline] fn from(fd: BorrowedFd<'a>) -> Self { // SAFETY: `BorrowedFd` ensures that the file descriptor is valid, and // the lifetime parameter on the resulting `ArgReg` ensures that the // result is bounded by the `BorrowedFd`'s lifetime. unsafe { raw_fd(fd.as_raw_fd()) }
}
}
/// Pass a raw file-descriptor argument. Most users should use [`ArgReg::from`] /// instead, to preserve I/O safety as long as possible. /// /// # Safety /// /// `fd` must be a valid open file descriptor. #[inline] pub(super) unsafefn raw_fd<'a, Num: ArgNumber>(fd: RawFd) -> ArgReg<'a, Num> { // Use `no_fd` when passing `-1` is intended. #[cfg(feature = "fs")]
debug_assert!(fd == crate::fs::CWD.as_raw_fd() || fd >= 0);
// Don't pass the `io_uring_register_files_skip` sentry value this way. #[cfg(feature = "io_uring")]
debug_assert_ne!(
fd, crate::io_uring::io_uring_register_files_skip().as_raw_fd()
);
// Linux doesn't look at the high bits beyond the `c_int`, so use // zero-extension rather than sign-extension because it's a smaller // instruction. let fd: c::c_int = fd;
pass_usize(fd as c::c_uint as usize)
}
/// Deliberately pass `-1` to a file-descriptor argument, for system calls /// like `mmap` where this indicates the argument is omitted. #[inline] pub(super) fn no_fd<'a, Num: ArgNumber>() -> ArgReg<'a, Num> {
pass_usize(!0_usize)
}
/// Convert an optional mutable reference into a `usize` for passing to a /// syscall. #[inline] pub(super) fn opt_mut<T: Sized, Num: ArgNumber>(t: Option<&mut T>) -> ArgReg<'_, Num> { // This optimizes into the equivalent of `transmute(t)`, and has the // advantage of not requiring `unsafe`. match t {
Some(t) => by_mut(t),
None => raw_arg(null_mut()),
}
}
/// Convert an optional immutable reference into a `usize` for passing to a /// syscall. #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] #[inline] pub(super) fn opt_ref<T: Sized, Num: ArgNumber>(t: Option<&T>) -> ArgReg<'_, Num> { // This optimizes into the equivalent of `transmute(t)`, and has the // advantage of not requiring `unsafe`. match t {
Some(t) => by_ref(t),
None => raw_arg(null_mut()),
}
}
/// Convert a `c_int` into an `ArgReg`. /// /// Be sure to use `raw_fd` to pass `RawFd` values. #[inline] pub(super) fn c_int<'a, Num: ArgNumber>(i: c::c_int) -> ArgReg<'a, Num> {
pass_usize(i as usize)
}
/// Convert a `c_uint` into an `ArgReg`. #[inline] pub(super) fn c_uint<'a, Num: ArgNumber>(i: c::c_uint) -> ArgReg<'a, Num> {
pass_usize(i as usize)
}
#[cfg(target_pointer_width = "64")] #[inline] pub(super) fn loff_t_from_u64<'a, Num: ArgNumber>(i: u64) -> ArgReg<'a, Num> { // `loff_t` is signed, but syscalls which expect `loff_t` return `EINVAL` // if it's outside the signed `i64` range, so we can silently cast.
pass_usize(i as usize)
}
impl<'a, Num: ArgNumber> From<OFlags> for ArgReg<'a, Num> { #[inline] fn from(oflags: OFlags) -> Self {
pass_usize(oflags_bits(oflags) as usize)
}
}
/// Convert an `OFlags` into a `u64` for use in the `open_how` struct. #[inline] pub(crate) fn oflags_for_open_how(oflags: OFlags) -> u64 {
u64::from(oflags_bits(oflags))
}
// When the deprecated "fs" aliases are removed, we can remove the "fs" // here too. #[cfg(any(feature = "fs", feature = "mount"))] impl<'a, Num: ArgNumber> From<crate::backend::mount::types::UnmountFlags> for ArgReg<'a, Num> { #[inline] fn from(flags: crate::backend::mount::types::UnmountFlags) -> Self {
c_uint(flags.bits())
}
}
/// Convert a `usize` returned from a syscall that effectively returns `()` on /// success. /// /// # Safety /// /// The caller must ensure that this is the return value of a syscall which /// just returns 0 on success. #[inline] pub(super) unsafefn ret(raw: RetReg<R0>) -> io::Result<()> {
try_decode_void(raw)
}
/// Convert a `usize` returned from a syscall that doesn't return on success. /// /// # Safety /// /// The caller must ensure that this is the return value of a syscall which /// doesn't return on success. #[cfg(any(feature = "event", feature = "runtime", feature = "system"))] #[inline] pub(super) unsafefn ret_error(raw: RetReg<R0>) -> io::Errno {
try_decode_error(raw)
}
/// Convert a `usize` returned from a syscall that effectively always returns /// `()`. /// /// # Safety /// /// The caller must ensure that this is the return value of a syscall which /// always returns `()`. #[inline] pub(super) unsafefn ret_infallible(raw: RetReg<R0>) { #[cfg(debug_assertions)]
{
try_decode_void(raw).unwrap()
} #[cfg(not(debug_assertions))]
drop(raw);
}
/// Convert a `usize` returned from a syscall that effectively returns a /// `c_int` on success. #[inline] pub(super) fn ret_c_int(raw: RetReg<R0>) -> io::Result<c::c_int> {
try_decode_c_int(raw)
}
/// Convert a `usize` returned from a syscall that effectively returns a /// `c_uint` on success. #[inline] pub(super) fn ret_c_uint(raw: RetReg<R0>) -> io::Result<c::c_uint> {
try_decode_c_uint(raw)
}
/// Convert a `usize` returned from a syscall that effectively returns a `u64` /// on success. #[cfg(target_pointer_width = "64")] #[inline] pub(super) fn ret_u64(raw: RetReg<R0>) -> io::Result<u64> {
try_decode_u64(raw)
}
/// Convert a `usize` returned from a syscall that effectively returns a /// `usize` on success. #[inline] pub(super) fn ret_usize(raw: RetReg<R0>) -> io::Result<usize> {
try_decode_usize(raw)
}
/// Convert a `usize` returned from a syscall that effectively always /// returns a `usize`. /// /// # Safety /// /// This function must only be used with return values from infallible /// syscalls. #[inline] pub(super) unsafefn ret_usize_infallible(raw: RetReg<R0>) -> usize { #[cfg(debug_assertions)]
{
try_decode_usize(raw).unwrap()
} #[cfg(not(debug_assertions))]
{
decode_usize_infallible(raw)
}
}
/// Convert a `c_int` returned from a syscall that effectively always /// returns a `c_int`. /// /// # Safety /// /// This function must only be used with return values from infallible /// syscalls. #[inline] pub(super) unsafefn ret_c_int_infallible(raw: RetReg<R0>) -> c::c_int { #[cfg(debug_assertions)]
{
try_decode_c_int(raw).unwrap()
} #[cfg(not(debug_assertions))]
{
decode_c_int_infallible(raw)
}
}
/// Convert a `c_uint` returned from a syscall that effectively always /// returns a `c_uint`. /// /// # Safety /// /// This function must only be used with return values from infallible /// syscalls. #[inline] pub(super) unsafefn ret_c_uint_infallible(raw: RetReg<R0>) -> c::c_uint { #[cfg(debug_assertions)]
{
try_decode_c_uint(raw).unwrap()
} #[cfg(not(debug_assertions))]
{
decode_c_uint_infallible(raw)
}
}
/// Convert a `usize` returned from a syscall that effectively returns an /// `OwnedFd` on success. /// /// # Safety /// /// The caller must ensure that this is the return value of a syscall which /// returns an owned file descriptor. #[inline] pub(super) unsafefn ret_owned_fd(raw: RetReg<R0>) -> io::Result<OwnedFd> { let raw_fd = try_decode_raw_fd(raw)?;
Ok(crate::backend::fd::OwnedFd::from_raw_fd(raw_fd))
}
/// Convert the return value of `dup2` and `dup3`. /// /// When these functions succeed, they return the same value as their second /// argument, so we don't construct a new `OwnedFd`. /// /// # Safety /// /// The caller must ensure that this is the return value of a syscall which /// returns a file descriptor. #[inline] pub(super) unsafefn ret_discarded_fd(raw: RetReg<R0>) -> io::Result<()> { let _raw_fd = try_decode_raw_fd(raw)?;
Ok(())
}
/// Convert a `usize` returned from a syscall that effectively returns a /// `*mut c_void` on success. #[inline] pub(super) fn ret_void_star(raw: RetReg<R0>) -> io::Result<*mut c::c_void> {
try_decode_void_star(raw)
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.30 Sekunden
(vorverarbeitet am 2026-06-20)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.