diff options
Diffstat (limited to 'vendor/rustix/src/weak.rs')
-rw-r--r-- | vendor/rustix/src/weak.rs | 286 |
1 files changed, 0 insertions, 286 deletions
diff --git a/vendor/rustix/src/weak.rs b/vendor/rustix/src/weak.rs deleted file mode 100644 index 3cda8e6..0000000 --- a/vendor/rustix/src/weak.rs +++ /dev/null @@ -1,286 +0,0 @@ -// Implementation derived from `weak` in Rust's -// library/std/src/sys/unix/weak.rs at revision -// fd0cb0cdc21dd9c06025277d772108f8d42cb25f. -// -// Ideally we should update to a newer version which doesn't need `dlsym`, -// however that depends on the `extern_weak` feature which is currently -// unstable. - -#![cfg_attr(linux_raw, allow(unsafe_code))] - -//! Support for "weak linkage" to symbols on Unix -//! -//! Some I/O operations we do in libstd require newer versions of OSes but we -//! need to maintain binary compatibility with older releases for now. In order -//! to use the new functionality when available we use this module for -//! detection. -//! -//! One option to use here is weak linkage, but that is unfortunately only -//! really workable on Linux. Hence, use dlsym to get the symbol value at -//! runtime. This is also done for compatibility with older versions of glibc, -//! and to avoid creating dependencies on `GLIBC_PRIVATE` symbols. It assumes -//! that we've been dynamically linked to the library the symbol comes from, -//! but that is currently always the case for things like libpthread/libc. -//! -//! A long time ago this used weak linkage for the `__pthread_get_minstack` -//! symbol, but that caused Debian to detect an unnecessarily strict versioned -//! dependency on libc6 (#23628). - -// There are a variety of `#[cfg]`s controlling which targets are involved in -// each instance of `weak!` and `syscall!`. Rather than trying to unify all of -// that, we'll just allow that some unix targets don't use this module at all. -#![allow(dead_code, unused_macros)] -#![allow(clippy::doc_markdown)] - -use crate::ffi::CStr; -use core::ffi::c_void; -use core::ptr::null_mut; -use core::sync::atomic::{self, AtomicPtr, Ordering}; -use core::{marker, mem}; - -const NULL: *mut c_void = null_mut(); -const INVALID: *mut c_void = 1 as *mut c_void; - -macro_rules! weak { - ($vis:vis fn $name:ident($($t:ty),*) -> $ret:ty) => ( - #[allow(non_upper_case_globals)] - $vis static $name: $crate::weak::Weak<unsafe extern fn($($t),*) -> $ret> = - $crate::weak::Weak::new(concat!(stringify!($name), '\0')); - ) -} - -pub(crate) struct Weak<F> { - name: &'static str, - addr: AtomicPtr<c_void>, - _marker: marker::PhantomData<F>, -} - -impl<F> Weak<F> { - pub(crate) const fn new(name: &'static str) -> Self { - Self { - name, - addr: AtomicPtr::new(INVALID), - _marker: marker::PhantomData, - } - } - - pub(crate) fn get(&self) -> Option<F> { - assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>()); - unsafe { - // Relaxed is fine here because we fence before reading through the - // pointer (see the comment below). - match self.addr.load(Ordering::Relaxed) { - INVALID => self.initialize(), - NULL => None, - addr => { - let func = mem::transmute_copy::<*mut c_void, 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 initialization. - #[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 { - NULL => None, - addr => Some(mem::transmute_copy::<*mut c_void, F>(&addr)), - } - } -} - -// To avoid having the `linux_raw` backend depend on the libc crate, just -// declare the few things we need in a module called `libc` so that `fetch` -// uses it. -#[cfg(linux_raw)] -mod libc { - use core::ptr; - use linux_raw_sys::ctypes::{c_char, c_void}; - - #[cfg(all(target_os = "android", target_pointer_width = "32"))] - pub(super) const RTLD_DEFAULT: *mut c_void = -1isize as *mut c_void; - #[cfg(not(all(target_os = "android", target_pointer_width = "32")))] - pub(super) const RTLD_DEFAULT: *mut c_void = ptr::null_mut(); - - extern "C" { - pub(super) fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void; - } - - #[test] - fn test_abi() { - assert_eq!(self::RTLD_DEFAULT, ::libc::RTLD_DEFAULT); - } -} - -unsafe fn fetch(name: &str) -> *mut c_void { - let name = match CStr::from_bytes_with_nul(name.as_bytes()) { - Ok(c_str) => c_str, - Err(..) => return null_mut(), - }; - libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr().cast()) -} - -#[cfg(not(linux_kernel))] -macro_rules! syscall { - (fn $name:ident($($arg_name:ident: $t:ty),*) via $_sys_name:ident -> $ret:ty) => ( - unsafe fn $name($($arg_name: $t),*) -> $ret { - weak! { fn $name($($t),*) -> $ret } - - if let Some(fun) = $name.get() { - fun($($arg_name),*) - } else { - libc_errno::set_errno(libc_errno::Errno(libc::ENOSYS)); - -1 - } - } - ) -} - -#[cfg(linux_kernel)] -macro_rules! syscall { - (fn $name:ident($($arg_name:ident: $t:ty),*) via $sys_name:ident -> $ret:ty) => ( - unsafe fn $name($($arg_name:$t),*) -> $ret { - // This looks like a hack, but `concat_idents` only accepts idents - // (not paths). - use libc::*; - - trait AsSyscallArg { - type SyscallArgType; - fn into_syscall_arg(self) -> Self::SyscallArgType; - } - - // Pass pointer types as pointers, to preserve provenance. - impl<T> AsSyscallArg for *mut T { - type SyscallArgType = *mut T; - fn into_syscall_arg(self) -> Self::SyscallArgType { self } - } - impl<T> AsSyscallArg for *const T { - type SyscallArgType = *const T; - fn into_syscall_arg(self) -> Self::SyscallArgType { self } - } - - // Pass `BorrowedFd` values as the integer value. - impl AsSyscallArg for $crate::fd::BorrowedFd<'_> { - type SyscallArgType = ::libc::c_int; - fn into_syscall_arg(self) -> Self::SyscallArgType { - $crate::fd::AsRawFd::as_raw_fd(&self) as _ - } - } - - // Coerce integer values into `c_long`. - impl AsSyscallArg for i8 { - type SyscallArgType = ::libc::c_int; - fn into_syscall_arg(self) -> Self::SyscallArgType { self.into() } - } - impl AsSyscallArg for u8 { - type SyscallArgType = ::libc::c_int; - fn into_syscall_arg(self) -> Self::SyscallArgType { self.into() } - } - impl AsSyscallArg for i16 { - type SyscallArgType = ::libc::c_int; - fn into_syscall_arg(self) -> Self::SyscallArgType { self.into() } - } - impl AsSyscallArg for u16 { - type SyscallArgType = ::libc::c_int; - fn into_syscall_arg(self) -> Self::SyscallArgType { self.into() } - } - impl AsSyscallArg for i32 { - type SyscallArgType = ::libc::c_int; - fn into_syscall_arg(self) -> Self::SyscallArgType { self } - } - impl AsSyscallArg for u32 { - type SyscallArgType = ::libc::c_uint; - fn into_syscall_arg(self) -> Self::SyscallArgType { self } - } - impl AsSyscallArg for usize { - type SyscallArgType = ::libc::c_ulong; - fn into_syscall_arg(self) -> Self::SyscallArgType { self as _ } - } - - // On 64-bit platforms, also coerce `i64` and `u64` since `c_long` - // is 64-bit and can hold those values. - #[cfg(target_pointer_width = "64")] - impl AsSyscallArg for i64 { - type SyscallArgType = ::libc::c_long; - fn into_syscall_arg(self) -> Self::SyscallArgType { self } - } - #[cfg(target_pointer_width = "64")] - impl AsSyscallArg for u64 { - type SyscallArgType = ::libc::c_ulong; - fn into_syscall_arg(self) -> Self::SyscallArgType { self } - } - - // `concat_idents` is [unstable], so we take an extra `sys_name` - // parameter and have our users do the concat for us for now. - // - // [unstable]: https://github.com/rust-lang/rust/issues/29599 - /* - syscall( - concat_idents!(SYS_, $name), - $($arg_name.into_syscall_arg()),* - ) as $ret - */ - - syscall($sys_name, $($arg_name.into_syscall_arg()),*) as $ret - } - ) -} - -macro_rules! weakcall { - ($vis:vis fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( - $vis unsafe fn $name($($arg_name: $t),*) -> $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 fail. - if let Some(fun) = $name.get() { - fun($($arg_name),*) - } else { - libc_errno::set_errno(libc_errno::Errno(libc::ENOSYS)); - -1 - } - } - ) -} - -/// A combination of `weakcall` and `syscall`. Use the libc function if it's -/// available, and fall back to `libc::syscall` otherwise. -macro_rules! weak_or_syscall { - ($vis:vis fn $name:ident($($arg_name:ident: $t:ty),*) via $sys_name:ident -> $ret:ty) => ( - $vis unsafe fn $name($($arg_name: $t),*) -> $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 fail. - if let Some(fun) = $name.get() { - fun($($arg_name),*) - } else { - syscall! { fn $name($($arg_name: $t),*) via $sys_name -> $ret } - $name($($arg_name),*) - } - } - ) -} |