1
Fork 0

Change the syntax of the internal weak! macro

Change the syntax to include parameter names and a trailing semicolon.

Motivation:
- Mirror the `syscall!` macro.
- Allow rustfmt to format it (when wrapped in parentheses).
- For better documentation (having the parameter names available in
  the source code is a bit nicer).
- Allow future improvements to this macro where we can sometimes use the
  symbol directly when it's statically known to be available.
This commit is contained in:
Mads Marquart 2025-03-26 15:23:47 +01:00
parent 65899c06f1
commit a7bafc0afc
9 changed files with 144 additions and 80 deletions

View file

@ -155,15 +155,15 @@ cfg_has_statx! {{
enum STATX_STATE{ Unknown = 0, Present, Unavailable } enum STATX_STATE{ Unknown = 0, Present, Unavailable }
static STATX_SAVED_STATE: AtomicU8 = AtomicU8::new(STATX_STATE::Unknown as u8); static STATX_SAVED_STATE: AtomicU8 = AtomicU8::new(STATX_STATE::Unknown as u8);
syscall! { syscall!(
fn statx( fn statx(
fd: c_int, fd: c_int,
pathname: *const c_char, pathname: *const c_char,
flags: c_int, flags: c_int,
mask: libc::c_uint, mask: libc::c_uint,
statxbuf: *mut libc::statx statxbuf: *mut libc::statx,
) -> c_int ) -> c_int;
} );
let statx_availability = STATX_SAVED_STATE.load(Ordering::Relaxed); let statx_availability = STATX_SAVED_STATE.load(Ordering::Relaxed);
if statx_availability == STATX_STATE::Unavailable as u8 { if statx_availability == STATX_STATE::Unavailable as u8 {
@ -1540,7 +1540,9 @@ impl File {
let times = [to_timespec(times.accessed)?, to_timespec(times.modified)?]; let times = [to_timespec(times.accessed)?, to_timespec(times.modified)?];
// futimens requires Android API level 19 // futimens requires Android API level 19
cvt(unsafe { cvt(unsafe {
weak!(fn futimens(c_int, *const libc::timespec) -> c_int); weak!(
fn futimens(fd: c_int, times: *const libc::timespec) -> c_int;
);
match futimens.get() { match futimens.get() {
Some(futimens) => futimens(self.as_raw_fd(), times.as_ptr()), Some(futimens) => futimens(self.as_raw_fd(), times.as_ptr()),
None => return Err(io::const_error!( None => return Err(io::const_error!(
@ -1556,7 +1558,9 @@ impl File {
use crate::sys::{time::__timespec64, weak::weak}; use crate::sys::{time::__timespec64, weak::weak};
// Added in glibc 2.34 // Added in glibc 2.34
weak!(fn __futimens64(libc::c_int, *const __timespec64) -> libc::c_int); weak!(
fn __futimens64(fd: c_int, times: *const __timespec64) -> c_int;
);
if let Some(futimens64) = __futimens64.get() { if let Some(futimens64) = __futimens64.get() {
let to_timespec = |time: Option<SystemTime>| time.map(|time| time.t.to_timespec64()) let to_timespec = |time: Option<SystemTime>| time.map(|time| time.t.to_timespec64())

View file

@ -232,14 +232,14 @@ impl FileDesc {
// implementation if `preadv` is not available. // implementation if `preadv` is not available.
#[cfg(all(target_os = "android", target_pointer_width = "64"))] #[cfg(all(target_os = "android", target_pointer_width = "64"))]
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
super::weak::syscall! { super::weak::syscall!(
fn preadv( fn preadv(
fd: libc::c_int, fd: libc::c_int,
iovec: *const libc::iovec, iovec: *const libc::iovec,
n_iovec: libc::c_int, n_iovec: libc::c_int,
offset: off64_t offset: off64_t,
) -> isize ) -> isize;
} );
let ret = cvt(unsafe { let ret = cvt(unsafe {
preadv( preadv(
@ -257,7 +257,14 @@ impl FileDesc {
// and its metadata from LLVM IR. // and its metadata from LLVM IR.
#[no_sanitize(cfi)] #[no_sanitize(cfi)]
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
super::weak::weak!(fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); super::weak::weak!(
fn preadv64(
fd: libc::c_int,
iovec: *const libc::iovec,
n_iovec: libc::c_int,
offset: off64_t,
) -> isize;
);
match preadv64.get() { match preadv64.get() {
Some(preadv) => { Some(preadv) => {
@ -286,7 +293,14 @@ impl FileDesc {
// use "weak" linking. // use "weak" linking.
#[cfg(target_vendor = "apple")] #[cfg(target_vendor = "apple")]
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
super::weak::weak!(fn preadv(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); super::weak::weak!(
fn preadv(
fd: libc::c_int,
iovec: *const libc::iovec,
n_iovec: libc::c_int,
offset: off64_t,
) -> isize;
);
match preadv.get() { match preadv.get() {
Some(preadv) => { Some(preadv) => {
@ -428,14 +442,14 @@ impl FileDesc {
// implementation if `pwritev` is not available. // implementation if `pwritev` is not available.
#[cfg(all(target_os = "android", target_pointer_width = "64"))] #[cfg(all(target_os = "android", target_pointer_width = "64"))]
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
super::weak::syscall! { super::weak::syscall!(
fn pwritev( fn pwritev(
fd: libc::c_int, fd: libc::c_int,
iovec: *const libc::iovec, iovec: *const libc::iovec,
n_iovec: libc::c_int, n_iovec: libc::c_int,
offset: off64_t offset: off64_t,
) -> isize ) -> isize;
} );
let ret = cvt(unsafe { let ret = cvt(unsafe {
pwritev( pwritev(
@ -450,7 +464,14 @@ impl FileDesc {
#[cfg(all(target_os = "android", target_pointer_width = "32"))] #[cfg(all(target_os = "android", target_pointer_width = "32"))]
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
super::weak::weak!(fn pwritev64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); super::weak::weak!(
fn pwritev64(
fd: libc::c_int,
iovec: *const libc::iovec,
n_iovec: libc::c_int,
offset: off64_t,
) -> isize;
);
match pwritev64.get() { match pwritev64.get() {
Some(pwritev) => { Some(pwritev) => {
@ -479,7 +500,14 @@ impl FileDesc {
// use "weak" linking. // use "weak" linking.
#[cfg(target_vendor = "apple")] #[cfg(target_vendor = "apple")]
pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
super::weak::weak!(fn pwritev(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); super::weak::weak!(
fn pwritev(
fd: libc::c_int,
iovec: *const libc::iovec,
n_iovec: libc::c_int,
offset: off64_t,
) -> isize;
);
match pwritev.get() { match pwritev.get() {
Some(pwritev) => { Some(pwritev) => {

View file

@ -604,16 +604,16 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) ->
_ => true, _ => true,
}; };
syscall! { syscall!(
fn copy_file_range( fn copy_file_range(
fd_in: libc::c_int, fd_in: libc::c_int,
off_in: *mut libc::loff_t, off_in: *mut libc::loff_t,
fd_out: libc::c_int, fd_out: libc::c_int,
off_out: *mut libc::loff_t, off_out: *mut libc::loff_t,
len: libc::size_t, len: libc::size_t,
flags: libc::c_uint flags: libc::c_uint,
) -> libc::ssize_t ) -> libc::ssize_t;
} );
fn probe_copy_file_range_support() -> u8 { fn probe_copy_file_range_support() -> u8 {
// In some cases, we cannot determine availability from the first // In some cases, we cannot determine availability from the first
@ -727,16 +727,16 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) ->
// Android builds use feature level 14, but the libc wrapper for splice is // Android builds use feature level 14, but the libc wrapper for splice is
// gated on feature level 21+, so we have to invoke the syscall directly. // gated on feature level 21+, so we have to invoke the syscall directly.
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
syscall! { syscall!(
fn splice( fn splice(
srcfd: libc::c_int, srcfd: libc::c_int,
src_offset: *const i64, src_offset: *const i64,
dstfd: libc::c_int, dstfd: libc::c_int,
dst_offset: *const i64, dst_offset: *const i64,
len: libc::size_t, len: libc::size_t,
flags: libc::c_int flags: libc::c_int,
) -> libc::ssize_t ) -> libc::ssize_t;
} );
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use libc::splice; use libc::splice;

View file

@ -424,18 +424,32 @@ mod imp {
let pages = PAGES.get_or_init(|| { let pages = PAGES.get_or_init(|| {
use crate::sys::weak::dlsym; use crate::sys::weak::dlsym;
dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int); dlsym!(
fn sysctlbyname(
name: *const libc::c_char,
oldp: *mut libc::c_void,
oldlenp: *mut libc::size_t,
newp: *const libc::c_void,
newlen: libc::size_t,
) -> libc::c_int;
);
let mut guard: usize = 0; let mut guard: usize = 0;
let mut size = size_of_val(&guard); let mut size = size_of_val(&guard);
let oid = c"security.bsd.stack_guard_page"; let oid = c"security.bsd.stack_guard_page";
match sysctlbyname.get() { match sysctlbyname.get() {
Some(fcn) if unsafe { Some(fcn)
fcn(oid.as_ptr(), if unsafe {
(&raw mut guard).cast(), fcn(
&raw mut size, oid.as_ptr(),
ptr::null_mut(), (&raw mut guard).cast(),
0) == 0 &raw mut size,
} => guard, ptr::null_mut(),
0,
) == 0
} =>
{
guard
}
_ => 1, _ => 1,
} }
}); });

View file

@ -193,11 +193,12 @@ impl Thread {
// and its metadata from LLVM IR. // and its metadata from LLVM IR.
#[no_sanitize(cfi)] #[no_sanitize(cfi)]
pub fn set_name(name: &CStr) { pub fn set_name(name: &CStr) {
weak! { weak!(
fn pthread_setname_np( fn pthread_setname_np(
libc::pthread_t, *const libc::c_char thread: libc::pthread_t,
) -> libc::c_int name: *const libc::c_char,
} ) -> libc::c_int;
);
if let Some(f) = pthread_setname_np.get() { if let Some(f) = pthread_setname_np.get() {
#[cfg(target_os = "nto")] #[cfg(target_os = "nto")]
@ -762,7 +763,9 @@ unsafe fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
// We use dlsym to avoid an ELF version dependency on GLIBC_PRIVATE. (#23628) // We use dlsym to avoid an ELF version dependency on GLIBC_PRIVATE. (#23628)
// We shouldn't really be using such an internal symbol, but there's currently // We shouldn't really be using such an internal symbol, but there's currently
// no other way to account for the TLS size. // no other way to account for the TLS size.
dlsym!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t); dlsym!(
fn __pthread_get_minstack(attr: *const libc::pthread_attr_t) -> libc::size_t;
);
match __pthread_get_minstack.get() { match __pthread_get_minstack.get() {
None => libc::PTHREAD_STACK_MIN, None => libc::PTHREAD_STACK_MIN,

View file

@ -123,7 +123,12 @@ impl Timespec {
// __clock_gettime64 was added to 32-bit arches in glibc 2.34, // __clock_gettime64 was added to 32-bit arches in glibc 2.34,
// and it handles both vDSO calls and ENOSYS fallbacks itself. // and it handles both vDSO calls and ENOSYS fallbacks itself.
weak!(fn __clock_gettime64(libc::clockid_t, *mut __timespec64) -> libc::c_int); weak!(
fn __clock_gettime64(
clockid: libc::clockid_t,
tp: *mut __timespec64,
) -> libc::c_int;
);
if let Some(clock_gettime64) = __clock_gettime64.get() { if let Some(clock_gettime64) = __clock_gettime64.get() {
let mut t = MaybeUninit::uninit(); let mut t = MaybeUninit::uninit();

View file

@ -29,7 +29,7 @@ use crate::{mem, ptr};
// We can use true weak linkage on ELF targets. // We can use true weak linkage on ELF targets.
#[cfg(all(unix, not(target_vendor = "apple")))] #[cfg(all(unix, not(target_vendor = "apple")))]
pub(crate) macro weak { pub(crate) macro weak {
(fn $name:ident($($t:ty),*) -> $ret:ty) => ( (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => (
let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = { let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
unsafe extern "C" { unsafe extern "C" {
#[linkage = "extern_weak"] #[linkage = "extern_weak"]
@ -62,10 +62,16 @@ impl<F: Copy> ExternWeak<F> {
} }
pub(crate) macro dlsym { pub(crate) macro dlsym {
(fn $name:ident($($t:ty),*) -> $ret:ty) => ( (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => (
dlsym!(fn $name($($t),*) -> $ret, stringify!($name)); dlsym!(
#[link_name = stringify!($name)]
fn $name($($param : $t),*) -> $ret;
);
), ),
(fn $name:ident($($t:ty),*) -> $ret:ty, $sym:expr) => ( (
#[link_name = $sym:expr]
fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;
) => (
static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> = static DLSYM: DlsymWeak<unsafe extern "C" fn($($t),*) -> $ret> =
DlsymWeak::new(concat!($sym, '\0')); DlsymWeak::new(concat!($sym, '\0'));
let $name = &DLSYM; let $name = &DLSYM;
@ -143,15 +149,15 @@ unsafe fn fetch(name: &str) -> *mut libc::c_void {
#[cfg(not(any(target_os = "linux", target_os = "android")))] #[cfg(not(any(target_os = "linux", target_os = "android")))]
pub(crate) macro syscall { pub(crate) macro syscall {
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => (
// FIXME(#115199): Rust currently omits weak function definitions // FIXME(#115199): Rust currently omits weak function definitions
// and its metadata from LLVM IR. // and its metadata from LLVM IR.
#[no_sanitize(cfi)] #[no_sanitize(cfi)]
unsafe fn $name($($arg_name: $t),*) -> $ret { unsafe fn $name($($param: $t),*) -> $ret {
weak! { fn $name($($t),*) -> $ret } weak!(fn $name($($param: $t),*) -> $ret;);
if let Some(fun) = $name.get() { if let Some(fun) = $name.get() {
fun($($arg_name),*) fun($($param),*)
} else { } else {
super::os::set_errno(libc::ENOSYS); super::os::set_errno(libc::ENOSYS);
-1 -1
@ -162,16 +168,18 @@ pub(crate) macro syscall {
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
pub(crate) macro syscall { pub(crate) macro syscall {
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( (
unsafe fn $name($($arg_name:$t),*) -> $ret { fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;
weak! { fn $name($($t),*) -> $ret } ) => (
unsafe fn $name($($param: $t),*) -> $ret {
weak!(fn $name($($param: $t),*) -> $ret;);
// Use a weak symbol from libc when possible, allowing `LD_PRELOAD` // Use a weak symbol from libc when possible, allowing `LD_PRELOAD`
// interposition, but if it's not found just use a raw syscall. // interposition, but if it's not found just use a raw syscall.
if let Some(fun) = $name.get() { if let Some(fun) = $name.get() {
fun($($arg_name),*) fun($($param),*)
} else { } else {
libc::syscall(libc::${concat(SYS_, $name)}, $($arg_name),*) as $ret libc::syscall(libc::${concat(SYS_, $name)}, $($param),*) as $ret
} }
} }
) )
@ -179,9 +187,9 @@ pub(crate) macro syscall {
#[cfg(any(target_os = "linux", target_os = "android"))] #[cfg(any(target_os = "linux", target_os = "android"))]
pub(crate) macro raw_syscall { pub(crate) macro raw_syscall {
(fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => (
unsafe fn $name($($arg_name:$t),*) -> $ret { unsafe fn $name($($param: $t),*) -> $ret {
libc::syscall(libc::${concat(SYS_, $name)}, $($arg_name),*) as $ret libc::syscall(libc::${concat(SYS_, $name)}, $($param),*) as $ret
} }
) )
} }

View file

@ -461,18 +461,20 @@ impl Command {
if #[cfg(target_os = "linux")] { if #[cfg(target_os = "linux")] {
use crate::sys::weak::weak; use crate::sys::weak::weak;
weak! { weak!(
fn pidfd_spawnp( fn pidfd_spawnp(
*mut libc::c_int, pidfd: *mut libc::c_int,
*const libc::c_char, path: *const libc::c_char,
*const libc::posix_spawn_file_actions_t, file_actions: *const libc::posix_spawn_file_actions_t,
*const libc::posix_spawnattr_t, attrp: *const libc::posix_spawnattr_t,
*const *mut libc::c_char, argv: *const *mut libc::c_char,
*const *mut libc::c_char envp: *const *mut libc::c_char,
) -> libc::c_int ) -> libc::c_int;
} );
weak! { fn pidfd_getpid(libc::c_int) -> libc::c_int } weak!(
fn pidfd_getpid(pidfd: libc::c_int) -> libc::c_int;
);
static PIDFD_SUPPORTED: AtomicU8 = AtomicU8::new(0); static PIDFD_SUPPORTED: AtomicU8 = AtomicU8::new(0);
const UNKNOWN: u8 = 0; const UNKNOWN: u8 = 0;
@ -593,19 +595,19 @@ impl Command {
// https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_addchdir.html. // https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_addchdir.html.
// The _np version is more widely available, though, so try that first. // The _np version is more widely available, though, so try that first.
weak! { weak!(
fn posix_spawn_file_actions_addchdir_np( fn posix_spawn_file_actions_addchdir_np(
*mut libc::posix_spawn_file_actions_t, file_actions: *mut libc::posix_spawn_file_actions_t,
*const libc::c_char path: *const libc::c_char,
) -> libc::c_int ) -> libc::c_int;
} );
weak! { weak!(
fn posix_spawn_file_actions_addchdir( fn posix_spawn_file_actions_addchdir(
*mut libc::posix_spawn_file_actions_t, file_actions: *mut libc::posix_spawn_file_actions_t,
*const libc::c_char path: *const libc::c_char,
) -> libc::c_int ) -> libc::c_int;
} );
posix_spawn_file_actions_addchdir_np posix_spawn_file_actions_addchdir_np
.get() .get()

View file

@ -73,13 +73,13 @@ fn getrandom(mut bytes: &mut [u8], insecure: bool) {
// A weak symbol allows interposition, e.g. for perf measurements that want to // A weak symbol allows interposition, e.g. for perf measurements that want to
// disable randomness for consistency. Otherwise, we'll try a raw syscall. // disable randomness for consistency. Otherwise, we'll try a raw syscall.
// (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28) // (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28)
syscall! { syscall!(
fn getrandom( fn getrandom(
buffer: *mut libc::c_void, buffer: *mut libc::c_void,
length: libc::size_t, length: libc::size_t,
flags: libc::c_uint flags: libc::c_uint,
) -> libc::ssize_t ) -> libc::ssize_t;
} );
static GETRANDOM_AVAILABLE: AtomicBool = AtomicBool::new(true); static GETRANDOM_AVAILABLE: AtomicBool = AtomicBool::new(true);
static GRND_INSECURE_AVAILABLE: AtomicBool = AtomicBool::new(true); static GRND_INSECURE_AVAILABLE: AtomicBool = AtomicBool::new(true);