Skip to content

Commit

Permalink
Merge pull request #4133 from geetanshjuneja/ioctl2
Browse files Browse the repository at this point in the history
Supported fioclex for ioctl on macos
  • Loading branch information
RalfJung authored Jan 11, 2025
2 parents bd99bc7 + 57bac2e commit ad1e4b3
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
30 changes: 30 additions & 0 deletions src/shims/unix/macos/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;

Expand Down Expand Up @@ -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" => {
Expand Down Expand Up @@ -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}");
}
}
}
20 changes: 20 additions & 0 deletions tests/pass-dep/libc/libc-fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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);
}
}
12 changes: 12 additions & 0 deletions tests/pass/shims/pipe.rs
Original file line number Diff line number Diff line change
@@ -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());
}

0 comments on commit ad1e4b3

Please sign in to comment.