Open
Description
This function provides a safe wrapper for the (Linux-specific) system call getresuid
.
use libc::uid_t;
use std::mem::MaybeUninit;
pub fn getresuid() -> (uid_t, uid_t, uid_t) {
let mut ruid = MaybeUninit::uninit();
let mut euid = MaybeUninit::uninit();
let mut suid = MaybeUninit::uninit();
unsafe {
let _ = libc::getresuid(ruid.as_mut_ptr(), euid.as_mut_ptr(), suid.as_mut_ptr());
(ruid.assume_init(), euid.assume_init(), suid.assume_init())
}
}
With rustc 1.87.0-nightly (2025-02-22 46420c9), on x86-64, suboptimal assembly code is generated:
playground::getresuid:
pushq %rbx
subq $16, %rsp
movq %rdi, %rbx
leaq 8(%rsp), %rsi
leaq 12(%rsp), %rdx
callq *getresuid@GOTPCREL(%rip)
movl 8(%rsp), %eax
movl 12(%rsp), %ecx
movl %eax, 4(%rbx)
movl %ecx, 8(%rbx)
movq %rbx, %rax
addq $16, %rsp
popq %rbx
retq
The 3-tuple return value is being returned by "invisible reference", i.e. caller supplied a pointer to space for 3 uid_t
(== u32
) quantities. The compiler could have had libc::getresuid
write all three of its outputs directly into that space, but instead it only had it write one of its outputs directly into that space, and supplied scratch stack locations for the other two, which then had to be copied into place.
Better code would be like this:
playground::getresuid:
pushq %rbx
movq %rdi, %rbx
leaq 4(%rdi), %rsi
leaq 8(%rdi), %rdx
callq *getresuid@GOTPCREL(%rip)
movq %rbx, %rax
popq %rbx
retq
This does not seem to be a regression, at least not from current stable.