mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Merge pull request #4914 from RalfJung/uname
Add a shim for uname systemcall
This commit is contained in:
@@ -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));
|
||||
}
|
||||
Reference in New Issue
Block a user