Merge pull request #4914 from RalfJung/uname

Add a shim for uname systemcall
This commit is contained in:
Ralf Jung
2026-03-22 11:13:02 +00:00
committed by GitHub
5 changed files with 116 additions and 0 deletions
+47
View File
@@ -272,6 +272,53 @@ fn unix_gettid(&mut self, link_name: &str) -> InterpResult<'tcx, Scalar> {
interp_ok(Scalar::from_u32(this.get_current_tid()))
}
/// `fields_size`, if present, says how large each field of the struct is.
fn uname(
&mut self,
uname: &OpTy<'tcx>,
fields_size: Option<&OpTy<'tcx>>,
) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
this.assert_target_os_is_unix("uname");
let uname_ptr = this.read_pointer(uname)?;
let fields_size = match fields_size {
None => None,
Some(size) => Some(this.read_scalar(size)?.to_i32()?),
};
if this.ptr_is_null(uname_ptr)? {
return this.set_last_error_and_return_i32(LibcError("EFAULT"));
}
let uname = this.deref_pointer_as(uname, this.libc_ty_layout("utsname"))?;
let arch = this.machine.tcx.sess.target.arch.desc_symbol();
// Values required by POSIX.
let mut values = vec![
("sysname", "Miri"),
("nodename", "Miri"),
("release", env!("CARGO_PKG_VERSION")),
("version", concat!("Miri ", env!("CARGO_PKG_VERSION"))),
("machine", arch.as_str()),
];
if matches!(this.machine.tcx.sess.target.os, Os::Linux | Os::Android) {
values.push(("domainname", "(none)"));
}
for (name, value) in values {
let field = this.project_field_named(&uname, name)?;
let size = field.layout().layout.size().bytes();
if fields_size.is_some_and(|fields_size| u64::try_from(fields_size) != Ok(size)) {
throw_unsup_format!(
"the fields size passed to `uname` does not match the type in the libc crate"
);
}
let (written, _) = this.write_c_str(value.as_bytes(), field.ptr(), size)?;
assert!(written); // All values should fit.
}
interp_ok(Scalar::from_i32(0))
}
/// The Apple-specific `int pthread_threadid_np(pthread_t thread, uint64_t *thread_id)`, which
/// allows querying the ID for arbitrary threads, identified by their pthread_t.
///
@@ -174,6 +174,21 @@ fn emulate_foreign_item_inner(
let result = this.getpid()?;
this.write_scalar(result, dest)?;
}
"uname" => {
// Not all Unixes have the `uname` symbol, e.g. FreeBSD does not.
this.check_target_os(
&[Os::Linux, Os::Android, Os::MacOs, Os::Solaris, Os::Illumos],
link_name,
)?;
let [uname] = this.check_shim_sig(
shim_sig!(extern "C" fn(*mut _) -> i32),
link_name,
abi,
args,
)?;
let result = this.uname(uname, None)?;
this.write_scalar(result, dest)?;
}
"sysconf" => {
let [val] = this.check_shim_sig(
shim_sig!(extern "C" fn(i32) -> isize),
@@ -165,6 +165,19 @@ fn emulate_foreign_item_inner(
let errno_place = this.last_error_place()?;
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
"__xuname" => {
// FreeBSD uses __xuname under the hood to implement uname, see:
// https://github.com/freebsd/freebsd-src/blob/3542d60fb8042474f66fbf2d779ed8c5a80d0f78/sys/sys/utsname.h#L64
// https://github.com/freebsd/freebsd-src/blob/3542d60fb8042474f66fbf2d779ed8c5a80d0f78/lib/libc/gen/uname.c#L44
let [size, uname] = this.check_shim_sig(
shim_sig!(extern "C" fn(i32, *mut _) -> i32),
link_name,
abi,
args,
)?;
let result = this.uname(uname, Some(size))?;
this.write_scalar(result, dest)?;
}
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
// These shims are enabled only when the caller is in the standard library.
@@ -3,6 +3,7 @@
#[path = "../../utils/libc.rs"]
mod libc_utils;
use std::time::{Duration, Instant};
use std::{env, mem, ptr};
@@ -0,0 +1,40 @@
//@ignore-target: windows # No libc
#[path = "../../utils/libc.rs"]
mod libc_utils;
use std::ffi::CStr;
use std::{io, ptr};
use libc_utils::*;
fn main() {
test_ok();
test_null_ptr();
}
fn test_ok() {
// SAFETY: all zeros for `utsname` is valid.
let mut uname: libc::utsname = unsafe { std::mem::zeroed() };
errno_check(unsafe { libc::uname(&mut uname) });
assert_eq!(unsafe { CStr::from_ptr(&uname.sysname as *const _) }, c"Miri");
assert_eq!(unsafe { CStr::from_ptr(&uname.nodename as *const _) }, c"Miri");
assert_eq!(
unsafe { CStr::from_ptr(&uname.release as *const _) }.to_str().unwrap(),
env!("CARGO_PKG_VERSION")
);
assert_eq!(unsafe { CStr::from_ptr(&uname.version as *const _) }, c"Miri 0.1.0");
assert_eq!(
unsafe { CStr::from_ptr(&uname.machine as *const _) }.to_str().unwrap(),
std::env::consts::ARCH
);
#[cfg(any(target_os = "linux", target_os = "android"))]
assert_eq!(unsafe { CStr::from_ptr(&uname.domainname as *const _) }, c"(none)");
}
fn test_null_ptr() {
let err = errno_result(unsafe { libc::uname(ptr::null_mut()) }).unwrap_err();
assert_eq!(err.raw_os_error(), Some(libc::EFAULT));
assert_eq!(io::Error::last_os_error().raw_os_error(), Some(libc::EFAULT));
}