Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions src/shims/unix/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let result = this.symlink(target, linkpath)?;
this.write_scalar(result, dest)?;
}
"fstat" => {
let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.fstat(fd, buf)?;
this.write_scalar(result, dest)?;
}
"rename" => {
let [oldpath, newpath] = this.check_shim_sig(
shim_sig!(extern "C" fn(*const _, *const _) -> i32),
Expand Down
4 changes: 2 additions & 2 deletions src/shims/unix/freebsd/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let result = this.macos_fbsd_solarish_lstat(path, buf)?;
this.write_scalar(result, dest)?;
}
"fstat" | "fstat@FBSD_1.0" => {
"fstat@FBSD_1.0" => {
let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
let result = this.fstat(fd, buf)?;
this.write_scalar(result, dest)?;
}
"readdir_r" | "readdir_r@FBSD_1.0" => {
Expand Down
37 changes: 18 additions & 19 deletions src/shims/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ impl UnixFileDescription for FileHandle {

impl<'tcx> EvalContextExtPrivate<'tcx> for crate::MiriInterpCx<'tcx> {}
trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> {
fn macos_fbsd_solarish_write_stat_buf(
fn write_stat_buf(
&mut self,
metadata: FileMetadata,
buf_op: &OpTy<'tcx>,
Expand All @@ -130,7 +130,11 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> {
let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0));
let mode = metadata.mode.to_uint(this.libc_ty_layout("mode_t").size)?;

let buf = this.deref_pointer_as(buf_op, this.libc_ty_layout("stat"))?;
// We do *not* use `deref_pointer_as` here since determining the right pointee type
// is highly non-trivial: it depends on which exact alias of the function was invoked
// (e.g. `fstat` vs `fstat64`), and then on FreeBSD it also depends on the ABI level
// which can be different between the libc used by std and the libc used by everyone else.
let buf = this.deref_pointer(buf_op)?;
this.write_int_fields_named(
&[
("st_dev", metadata.dev.into()),
Expand All @@ -141,8 +145,11 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> {
("st_gid", metadata.gid.into()),
("st_rdev", 0),
("st_atime", access_sec.into()),
("st_atime_nsec", access_nsec.into()),
("st_mtime", modified_sec.into()),
("st_mtime_nsec", modified_nsec.into()),
("st_ctime", 0),
("st_ctime_nsec", 0),
("st_size", metadata.size.into()),
("st_blocks", 0),
("st_blksize", 0),
Expand All @@ -153,9 +160,6 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> {
if matches!(&this.tcx.sess.target.os, Os::MacOs | Os::FreeBsd) {
this.write_int_fields_named(
&[
("st_atime_nsec", access_nsec.into()),
("st_mtime_nsec", modified_nsec.into()),
("st_ctime_nsec", 0),
("st_birthtime", created_sec.into()),
("st_birthtime_nsec", created_nsec.into()),
("st_flags", 0),
Expand Down Expand Up @@ -550,7 +554,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Err(err) => return this.set_last_error_and_return_i32(err),
};

interp_ok(Scalar::from_i32(this.macos_fbsd_solarish_write_stat_buf(metadata, buf_op)?))
interp_ok(Scalar::from_i32(this.write_stat_buf(metadata, buf_op)?))
}

// `lstat` is used to get symlink metadata.
Expand Down Expand Up @@ -583,22 +587,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Err(err) => return this.set_last_error_and_return_i32(err),
};

interp_ok(Scalar::from_i32(this.macos_fbsd_solarish_write_stat_buf(metadata, buf_op)?))
interp_ok(Scalar::from_i32(this.write_stat_buf(metadata, buf_op)?))
}

fn macos_fbsd_solarish_fstat(
&mut self,
fd_op: &OpTy<'tcx>,
buf_op: &OpTy<'tcx>,
) -> InterpResult<'tcx, Scalar> {
fn fstat(&mut self, fd_op: &OpTy<'tcx>, buf_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();

if !matches!(&this.tcx.sess.target.os, Os::MacOs | Os::FreeBsd | Os::Solaris | Os::Illumos)
{
panic!(
"`macos_fbsd_solaris_fstat` should not be called on {}",
this.tcx.sess.target.os
);
if !matches!(
&this.tcx.sess.target.os,
Os::MacOs | Os::FreeBsd | Os::Solaris | Os::Illumos | Os::Linux
) {
panic!("`fstat` should not be called on {}", this.tcx.sess.target.os);
}

let fd = this.read_scalar(fd_op)?.to_i32()?;
Expand All @@ -614,7 +613,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
Ok(metadata) => metadata,
Err(err) => return this.set_last_error_and_return_i32(err),
};
interp_ok(Scalar::from_i32(this.macos_fbsd_solarish_write_stat_buf(metadata, buf_op)?))
interp_ok(Scalar::from_i32(this.write_stat_buf(metadata, buf_op)?))
}

fn linux_statx(
Expand Down
1 change: 0 additions & 1 deletion src/shims/unix/linux/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?;
this.write_scalar(result, dest)?;
}

// epoll, eventfd
"epoll_create1" => {
let [flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
Expand Down
4 changes: 2 additions & 2 deletions src/shims/unix/macos/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let result = this.macos_fbsd_solarish_lstat(path, buf)?;
this.write_scalar(result, dest)?;
}
"fstat" | "fstat64" | "fstat$INODE64" => {
"fstat$INODE64" => {
let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
let result = this.fstat(fd, buf)?;
this.write_scalar(result, dest)?;
}
"opendir$INODE64" => {
Expand Down
5 changes: 0 additions & 5 deletions src/shims/unix/solarish/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let result = this.macos_fbsd_solarish_lstat(path, buf)?;
this.write_scalar(result, dest)?;
}
"fstat" | "fstat64" => {
let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.macos_fbsd_solarish_fstat(fd, buf)?;
this.write_scalar(result, dest)?;
}
"readdir" => {
let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
let result = this.readdir64("dirent", dirp)?;
Expand Down
36 changes: 36 additions & 0 deletions tests/pass-dep/libc/libc-fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ fn main() {
test_posix_fallocate::<libc::off64_t>(libc::posix_fallocate64);
#[cfg(target_os = "linux")]
test_sync_file_range();
test_fstat();
test_isatty();
test_read_and_uninit();
test_nofollow_not_symlink();
Expand Down Expand Up @@ -452,6 +453,41 @@ fn test_sync_file_range() {
assert_eq!(result_2, 0);
}

fn test_fstat() {
use std::mem::MaybeUninit;
use std::os::unix::io::AsRawFd;

let path = utils::prepare_with_content("miri_test_libc_fstat.txt", b"hello");
let file = File::open(&path).unwrap();
let fd = file.as_raw_fd();

let mut stat = MaybeUninit::<libc::stat>::uninit();
let res = unsafe { libc::fstat(fd, stat.as_mut_ptr()) };
assert_eq!(res, 0);
let stat = unsafe { stat.assume_init_ref() };

assert_eq!(stat.st_size, 5);
assert_eq!(stat.st_mode & libc::S_IFMT, libc::S_IFREG);

// Check that all fields are initialized.
let _st_nlink = stat.st_nlink;
let _st_blksize = stat.st_blksize;
let _st_blocks = stat.st_blocks;
let _st_ino = stat.st_ino;
let _st_dev = stat.st_dev;
let _st_uid = stat.st_uid;
let _st_gid = stat.st_gid;
let _st_rdev = stat.st_rdev;
let _st_atime = stat.st_atime;
let _st_mtime = stat.st_mtime;
let _st_ctime = stat.st_ctime;
let _st_atime_nsec = stat.st_atime_nsec;
let _st_mtime_nsec = stat.st_mtime_nsec;
let _st_ctime_nsec = stat.st_ctime_nsec;

remove_file(&path).unwrap();
}

fn test_isatty() {
// Testing whether our isatty shim returns the right value would require controlling whether
// these streams are actually TTYs, which is hard.
Expand Down