Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supported fioclex for ioctl on macos #4129

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0ea7121
Supported fioclex for ioctl on macos
geetanshjuneja Jan 9, 2025
1cbc0fd
cleanup
geetanshjuneja Jan 9, 2025
ac360ed
nits
geetanshjuneja Jan 9, 2025
77d4039
Added ioctl test
geetanshjuneja Jan 9, 2025
a99984c
fmt
geetanshjuneja Jan 9, 2025
18d5dcc
nits
geetanshjuneja Jan 9, 2025
add00c1
Fixed ioctl and added pipe test
geetanshjuneja Jan 10, 2025
37f7c2f
nits
geetanshjuneja Jan 10, 2025
1bcf34e
ignore pipe test for window
geetanshjuneja Jan 10, 2025
e52fafb
Preparing for merge from rustc
RalfJung Jan 10, 2025
31f6350
disable threading tests on freebsd for now
RalfJung Jan 10, 2025
11f70f2
fix clippy warning
RalfJung Jan 10, 2025
3dd4e1e
Merge pull request #4131 from RalfJung/rustup
RalfJung Jan 10, 2025
1f51d82
Switched FreeBSD to pthread_setname_np
YohDeadfall Jan 10, 2025
bd99bc7
Merge pull request #4132 from YohDeadfall/freebsd-thread-name-changes
oli-obk Jan 10, 2025
2f17551
minor changes
geetanshjuneja Jan 11, 2025
d1e52ee
Supported fioclex for ioctl on macos
geetanshjuneja Jan 11, 2025
cecd39c
Merge branch 'ioctl' of github.com:geetanshjuneja/miri into ioctl
geetanshjuneja Jan 11, 2025
386a182
Supported fioclex for ioctl on macos
geetanshjuneja Jan 11, 2025
063db4f
Supported fioclex for ioctl on macos
geetanshjuneja Jan 9, 2025
4e08e23
cleanup
geetanshjuneja Jan 9, 2025
05626b7
nits
geetanshjuneja Jan 9, 2025
433d076
Added ioctl test
geetanshjuneja Jan 9, 2025
04ba690
fmt
geetanshjuneja Jan 9, 2025
446fb77
nits
geetanshjuneja Jan 9, 2025
02bd4e3
Fixed ioctl and added pipe test
geetanshjuneja Jan 10, 2025
bb524e4
nits
geetanshjuneja Jan 10, 2025
d3d647f
minor changes
geetanshjuneja Jan 11, 2025
68fc8e6
Merge branch 'ioctl' of github.com:geetanshjuneja/miri into ioctl
geetanshjuneja Jan 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rust-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ad211ced81509462cdfe4c29ed10f97279a0acae
252b07bba419a075acfa1fa85d66683e9623c281
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
2 changes: 1 addition & 1 deletion src/shims/native_lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
// Functions with no declared return type (i.e., the default return)
// have the output_type `Tuple([])`.
ty::Tuple(t_list) if t_list.len() == 0 => {
ty::Tuple(t_list) if t_list.is_empty() => {
unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) };
return interp_ok(ImmTy::uninit(dest.layout));
}
Expand Down
27 changes: 18 additions & 9 deletions src/shims/unix/freebsd/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,38 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let this = self.eval_context_mut();
match link_name.as_str() {
// Threading
"pthread_set_name_np" => {
"pthread_setname_np" => {
let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?;
let max_len = usize::MAX; // FreeBSD does not seem to have a limit.
// FreeBSD's pthread_set_name_np does not return anything.
this.pthread_setname_np(
let res = match this.pthread_setname_np(
this.read_scalar(thread)?,
this.read_scalar(name)?,
max_len,
/* truncate */ false,
)?;
)? {
ThreadNameResult::Ok => Scalar::from_u32(0),
ThreadNameResult::NameTooLong => unreachable!(),
ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"),
};
this.write_scalar(res, dest)?;
}
"pthread_get_name_np" => {
"pthread_getname_np" => {
let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?;
// FreeBSD's pthread_get_name_np does not return anything
// and uses strlcpy, which truncates the resulting value,
// FreeBSD's pthread_getname_np uses strlcpy, which truncates the resulting value,
// but always adds a null terminator (except for zero-sized buffers).
// https://github.com/freebsd/freebsd-src/blob/c2d93a803acef634bd0eede6673aeea59e90c277/lib/libthr/thread/thr_info.c#L119-L144
this.pthread_getname_np(
let res = match this.pthread_getname_np(
this.read_scalar(thread)?,
this.read_scalar(name)?,
this.read_scalar(len)?,
/* truncate */ true,
)?;
)? {
ThreadNameResult::Ok => Scalar::from_u32(0),
// `NameTooLong` is possible when the buffer is zero sized,
ThreadNameResult::NameTooLong => Scalar::from_u32(0),
ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"),
};
this.write_scalar(res, dest)?;
}

// File related shims
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);
}
}
54 changes: 24 additions & 30 deletions tests/pass-dep/libc/pthread-threadname.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,13 @@ fn main() {

fn set_thread_name(name: &CStr) -> i32 {
cfg_if::cfg_if! {
if #[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))] {
if #[cfg(any(
target_os = "linux",
target_os = "freebsd",
target_os = "illumos",
target_os = "solaris"
))] {
unsafe { libc::pthread_setname_np(libc::pthread_self(), name.as_ptr().cast()) }
} else if #[cfg(target_os = "freebsd")] {
// pthread_set_name_np does not return anything
unsafe { libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr().cast()) };
0
} else if #[cfg(target_os = "macos")] {
unsafe { libc::pthread_setname_np(name.as_ptr().cast()) }
} else {
Expand All @@ -47,19 +48,14 @@ fn main() {
cfg_if::cfg_if! {
if #[cfg(any(
target_os = "linux",
target_os = "freebsd",
target_os = "illumos",
target_os = "solaris",
target_os = "macos"
))] {
unsafe {
libc::pthread_getname_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len())
}
} else if #[cfg(target_os = "freebsd")] {
// pthread_get_name_np does not return anything
unsafe {
libc::pthread_get_name_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len())
};
0
} else {
compile_error!("get_thread_name not supported for this OS")
}
Expand Down Expand Up @@ -201,27 +197,25 @@ fn main() {
.unwrap();

// Now set the name for a non-existing thread and verify error codes.
// (FreeBSD doesn't return an error code.)
#[cfg(not(target_os = "freebsd"))]
{
let invalid_thread = 0xdeadbeef;
let error = {
cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] {
libc::ENOENT
} else {
libc::ESRCH
}
let invalid_thread = 0xdeadbeef;
let error = {
cfg_if::cfg_if! {
if #[cfg(target_os = "linux")] {
libc::ENOENT
} else {
libc::ESRCH
}
};
#[cfg(not(target_os = "macos"))]
{
// macOS has no `setname` function accepting a thread id as the first argument.
let res = unsafe { libc::pthread_setname_np(invalid_thread, [0].as_ptr()) };
assert_eq!(res, error);
}
let mut buf = [0; 64];
let res = unsafe { libc::pthread_getname_np(invalid_thread, buf.as_mut_ptr(), buf.len()) };
};

#[cfg(not(target_os = "macos"))]
{
// macOS has no `setname` function accepting a thread id as the first argument.
let res = unsafe { libc::pthread_setname_np(invalid_thread, [0].as_ptr()) };
assert_eq!(res, error);
}

let mut buf = [0; 64];
let res = unsafe { libc::pthread_getname_np(invalid_thread, buf.as_mut_ptr(), buf.len()) };
assert_eq!(res, error);
}
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());
}
Loading