Merge pull request #4133 from geetanshjuneja/ioctl2

Supported fioclex for ioctl on macos
This commit is contained in:
Ralf Jung 2025-01-11 18:13:32 +00:00 committed by GitHub
commit fcb64d3af0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 70 additions and 0 deletions

View file

@ -262,6 +262,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
})
}
/// Helper function to get a `libc` constant as an `u64`.
fn eval_libc_u64(&self, name: &str) -> u64 {
// TODO: Cache the result.
self.eval_libc(name).to_u64().unwrap_or_else(|_err| {
panic!("required libc item has unexpected type (not `u64`): {name}")
})
}
/// Helper function to get a `windows` constant as a `Scalar`.
fn eval_windows(&self, module: &str, name: &str) -> Scalar {
self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal", "windows", module, name])

View file

@ -3,6 +3,7 @@ use rustc_span::Symbol;
use rustc_target::callconv::{Conv, FnAbi};
use super::sync::EvalContextExt as _;
use crate::helpers::check_min_arg_count;
use crate::shims::unix::*;
use crate::*;
@ -67,6 +68,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let result = this.realpath(path, resolved_path)?;
this.write_scalar(result, dest)?;
}
"ioctl" => {
// `ioctl` is variadic. The argument count is checked based on the first argument
// in `this.ioctl()`, so we do not use `check_shim` here.
this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?;
let result = this.ioctl(args)?;
this.write_scalar(result, dest)?;
}
// Environment related shims
"_NSGetEnviron" => {
@ -234,4 +242,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
interp_ok(EmulateItemResult::NeedsReturn)
}
fn ioctl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();
let fioclex = this.eval_libc_u64("FIOCLEX");
let [fd_num, cmd] = check_min_arg_count("ioctl", args)?;
let fd_num = this.read_scalar(fd_num)?.to_i32()?;
let cmd = this.read_scalar(cmd)?.to_u64()?;
if cmd == fioclex {
// Since we don't support `exec`, this is a NOP. However, we want to
// return EBADF if the FD is invalid.
if this.machine.fds.is_fd_num(fd_num) {
interp_ok(Scalar::from_i32(0))
} else {
this.set_last_error_and_return_i32(LibcError("EBADF"))
}
} else {
throw_unsup_format!("ioctl: unsupported command {cmd:#x}");
}
}
}

View file

@ -38,6 +38,8 @@ fn main() {
test_isatty();
test_read_and_uninit();
test_nofollow_not_symlink();
#[cfg(target_os = "macos")]
test_ioctl();
}
fn test_file_open_unix_allow_two_args() {
@ -431,3 +433,21 @@ fn test_nofollow_not_symlink() {
let ret = unsafe { libc::open(cpath.as_ptr(), libc::O_NOFOLLOW | libc::O_CLOEXEC) };
assert!(ret >= 0);
}
#[cfg(target_os = "macos")]
fn test_ioctl() {
let path = utils::prepare_with_content("miri_test_libc_ioctl.txt", &[]);
let mut name = path.into_os_string();
name.push("\0");
let name_ptr = name.as_bytes().as_ptr().cast::<libc::c_char>();
unsafe {
// 100 surely is an invalid FD.
assert_eq!(libc::ioctl(100, libc::FIOCLEX), -1);
let errno = std::io::Error::last_os_error().raw_os_error().unwrap();
assert_eq!(errno, libc::EBADF);
let fd = libc::open(name_ptr, libc::O_RDONLY);
assert_eq!(libc::ioctl(fd, libc::FIOCLEX), 0);
}
}

View file

@ -0,0 +1,12 @@
//@ignore-target: windows
#![feature(anonymous_pipe)]
use std::io::{Read, Write};
fn main() {
let (mut ping_rx, mut ping_tx) = std::pipe::pipe().unwrap();
ping_tx.write(b"hello").unwrap();
let mut buf: [u8; 5] = [0; 5];
ping_rx.read(&mut buf).unwrap();
assert_eq!(&buf, "hello".as_bytes());
}