about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2025-01-11 18:13:32 +0000
committerGitHub <noreply@github.com>2025-01-11 18:13:32 +0000
commitfcb64d3af06e2febea93a4701b49c7e5ab7d45d6 (patch)
tree489f9482e640b53c37e2f62f9061971ebc244a78
parenta2c10e45147206221ae5195a6f1bb010b564a9e6 (diff)
parentac7d9a1a944a821b74b7e97984a007ef0538cdce (diff)
downloadrust-fcb64d3af06e2febea93a4701b49c7e5ab7d45d6.tar.gz
rust-fcb64d3af06e2febea93a4701b49c7e5ab7d45d6.zip
Merge pull request #4133 from geetanshjuneja/ioctl2
Supported fioclex for ioctl on macos
-rw-r--r--src/tools/miri/src/helpers.rs8
-rw-r--r--src/tools/miri/src/shims/unix/macos/foreign_items.rs30
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-fs.rs20
-rw-r--r--src/tools/miri/tests/pass/shims/pipe.rs12
4 files changed, 70 insertions, 0 deletions
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index adfec33beac..ca8dbdac125 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -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])
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index aa291639a6d..2afe0b5cd30 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -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}");
+        }
+    }
 }
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
index f85abe2cc43..129b18d8e59 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
@@ -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);
+    }
+}
diff --git a/src/tools/miri/tests/pass/shims/pipe.rs b/src/tools/miri/tests/pass/shims/pipe.rs
new file mode 100644
index 00000000000..d547b2b1ccb
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/pipe.rs
@@ -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());
+}