Skip to content

Commit

Permalink
freebsd add *stat calls interception support
Browse files Browse the repository at this point in the history
  • Loading branch information
devnexen committed Nov 23, 2023
1 parent d251208 commit a04ac72
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 45 deletions.
3 changes: 2 additions & 1 deletion ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ case $HOST_TARGET in
MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align
MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs fs atomic env align
MIRI_TEST_TARGET=i686-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs fs atomic env align
MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm
MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm
Expand Down
11 changes: 11 additions & 0 deletions src/shims/unix/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
"lseek64" => {
let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let offset = this.read_scalar(offset)?.to_i64()?;
let whence = this.read_scalar(whence)?.to_i32()?;
let result = this.lseek64(fd, offset, whence)?;
this.write_scalar(result, dest)?;
}
"lseek" => {
let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let offset = this.read_target_isize(offset)?;
let whence = this.read_scalar(whence)?.to_i32()?;
let result = this.lseek64(fd, offset, whence)?;
this.write_scalar(result, dest)?;
}
Expand Down
26 changes: 26 additions & 0 deletions src/shims/unix/freebsd/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use rustc_target::spec::abi::Abi;

use crate::*;
use shims::foreign_items::EmulateForeignItemResult;
use shims::unix::fs::EvalContextExt as _;
use shims::unix::thread::EvalContextExt as _;

pub fn is_dyn_sym(_name: &str) -> bool {
Expand Down Expand Up @@ -63,6 +64,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
}

// File related shims
"stat" | "stat@FBSD_1.0" => {
let [path, buf] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.macos_fbsd_stat(path, buf)?;
this.write_scalar(result, dest)?;
}
"lstat" | "lstat@FBSD_1.0" => {
let [path, buf] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.macos_fbsd_lstat(path, buf)?;
this.write_scalar(result, dest)?;
}
"fstat" | "fstat@FBSD_1.0" => {
let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.macos_fbsd_fstat(fd, buf)?;
this.write_scalar(result, dest)?;
}
"readdir_r" | "readdir_r@FBSD_1.0" => {
let [dirp, entry, result] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
this.write_scalar(result, dest)?;
}

// errno
"__error" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
Expand Down
74 changes: 46 additions & 28 deletions src/shims/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -827,18 +827,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {

fn lseek64(
&mut self,
fd_op: &OpTy<'tcx, Provenance>,
offset_op: &OpTy<'tcx, Provenance>,
whence_op: &OpTy<'tcx, Provenance>,
fd: i32,
offset: i64,
whence: i32,
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();

// Isolation check is done via `FileDescriptor` trait.

let fd = this.read_scalar(fd_op)?.to_i32()?;
let offset = this.read_scalar(offset_op)?.to_i64()?;
let whence = this.read_scalar(whence_op)?.to_i32()?;

let seek_from = if whence == this.eval_libc_i32("SEEK_SET") {
SeekFrom::Start(u64::try_from(offset).unwrap())
} else if whence == this.eval_libc_i32("SEEK_CUR") {
Expand All @@ -856,7 +852,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) {
let result = file_descriptor
.seek(communicate, seek_from)?
.map(|offset| i64::try_from(offset).unwrap());
.map(|offset| offset.try_into().unwrap());
this.try_unwrap_io_result(result)?
} else {
this.handle_not_found()?
Expand Down Expand Up @@ -911,13 +907,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.try_unwrap_io_result(result)
}

fn macos_stat(
fn macos_fbsd_stat(
&mut self,
path_op: &OpTy<'tcx, Provenance>,
buf_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
this.assert_target_os("macos", "stat");

if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
panic!("`macos_fbsd_stat` should not be called on {}", this.tcx.sess.target.os);
}

let path_scalar = this.read_pointer(path_op)?;
let path = this.read_path_from_c_str(path_scalar)?.into_owned();
Expand All @@ -940,13 +939,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}

// `lstat` is used to get symlink metadata.
fn macos_lstat(
fn macos_fbsd_lstat(
&mut self,
path_op: &OpTy<'tcx, Provenance>,
buf_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
this.assert_target_os("macos", "lstat");

if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
panic!("`macos_fbsd_lstat` should not be called on {}", this.tcx.sess.target.os);
}

let path_scalar = this.read_pointer(path_op)?;
let path = this.read_path_from_c_str(path_scalar)?.into_owned();
Expand All @@ -967,14 +969,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
}

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

this.assert_target_os("macos", "fstat");
if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
panic!("`macos_fbsd_fstat` should not be called on {}", this.tcx.sess.target.os);
}

let fd = this.read_scalar(fd_op)?.to_i32()?;

Expand Down Expand Up @@ -1213,7 +1217,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let this = self.eval_context_mut();

#[cfg_attr(not(unix), allow(unused_variables))]
let mode = if this.tcx.sess.target.os == "macos" {
let mode = if matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
u32::from(this.read_scalar(mode_op)?.to_u16()?)
} else {
this.read_scalar(mode_op)?.to_u32()?
Expand Down Expand Up @@ -1385,15 +1389,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
Ok(Scalar::from_maybe_pointer(entry, this))
}

fn macos_readdir_r(
fn macos_fbsd_readdir_r(
&mut self,
dirp_op: &OpTy<'tcx, Provenance>,
entry_op: &OpTy<'tcx, Provenance>,
result_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();

this.assert_target_os("macos", "readdir_r");
if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
panic!("`macos_fbsd_readdir_r` should not be called on {}", this.tcx.sess.target.os);
}

let dirp = this.read_target_usize(dirp_op)?;

Expand Down Expand Up @@ -1424,7 +1430,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// }

let entry_place = this.deref_pointer_as(entry_op, this.libc_ty_layout("dirent"))?;
let name_place = this.project_field(&entry_place, 5)?;
let name_place = this.project_field_named(&entry_place, "d_name")?;

let file_name = dir_entry.file_name(); // not a Path as there are no separators!
let (name_fits, file_name_buf_len) = this.write_os_str_to_c_str(
Expand All @@ -1448,16 +1454,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {

let file_type = this.file_type_to_d_type(dir_entry.file_type())?;

this.write_int_fields_named(
&[
("d_ino", ino.into()),
("d_seekoff", 0),
("d_reclen", 0),
("d_namlen", file_name_len.into()),
("d_type", file_type.into()),
],
&entry_place,
)?;
if this.tcx.sess.target.os == "macos" {
this.write_int_fields_named(
&[
("d_ino", ino.into()),
("d_seekoff", 0),
("d_reclen", 0),
("d_namlen", file_name_len.into()),
("d_type", file_type.into()),
],
&entry_place,
)?;
} else {
this.write_int_fields_named(
&[
("d_fileno", ino.into()),
("d_reclen", 0),
("d_type", file_type.into()),
("d_namlen", file_name_len.into()),
],
&entry_place,
)?;
}

let result_place = this.deref_pointer(result_op)?;
this.write_scalar(this.read_scalar(entry_op)?, &result_place)?;
Expand Down
15 changes: 4 additions & 11 deletions src/shims/unix/macos/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"stat" | "stat64" | "stat$INODE64" => {
let [path, buf] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.macos_stat(path, buf)?;
let result = this.macos_fbsd_stat(path, buf)?;
this.write_scalar(result, dest)?;
}
"lstat" | "lstat64" | "lstat$INODE64" => {
let [path, buf] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.macos_lstat(path, buf)?;
let result = this.macos_fbsd_lstat(path, buf)?;
this.write_scalar(result, dest)?;
}
"fstat" | "fstat64" | "fstat$INODE64" => {
let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.macos_fstat(fd, buf)?;
let result = this.macos_fbsd_fstat(fd, buf)?;
this.write_scalar(result, dest)?;
}
"opendir$INODE64" => {
Expand All @@ -62,14 +62,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"readdir_r" | "readdir_r$INODE64" => {
let [dirp, entry, result] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let result = this.macos_readdir_r(dirp, entry, result)?;
this.write_scalar(result, dest)?;
}
"lseek" => {
let [fd, offset, whence] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
// macOS is 64bit-only, so this is lseek64
let result = this.lseek64(fd, offset, whence)?;
let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
this.write_scalar(result, dest)?;
}
"realpath$DARWIN_EXTSN" => {
Expand Down
1 change: 0 additions & 1 deletion tests/pass-dep/shims/libc-fs-with-isolation.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//@ignore-target-windows: no libc on Windows
//@ignore-target-freebsd: FIXME needs foreign function `stat@FBSD_1.0`
//@compile-flags: -Zmiri-isolation-error=warn-nobacktrace
//@normalize-stderr-test: "(stat(x)?)" -> "$$STAT"

Expand Down
13 changes: 9 additions & 4 deletions tests/pass/shims/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@
#![feature(io_error_more)]
#![feature(io_error_uncategorized)]

use std::collections::HashMap;
use std::ffi::OsString;
use std::fs::{
canonicalize, create_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, rename,
File, OpenOptions,
canonicalize, create_dir, read_link, remove_dir_all, remove_file, rename, File, OpenOptions,
};
use std::io::{Error, ErrorKind, IsTerminal, Read, Result, Seek, SeekFrom, Write};

Check failure on line 10 in tests/pass/shims/fs.rs

View workflow job for this annotation

GitHub Actions / build (ubuntu-latest, x86_64-unknown-linux-gnu)

Unmatched diagnostics

Error: unused import: `IsTerminal`
use std::path::{Path, PathBuf};
Expand All @@ -18,6 +15,7 @@ mod utils;

fn main() {
test_path_conversion();
#[cfg(not(all(target_os = "freebsd", target_pointer_width = "32")))]
test_file();
test_file_clone();
test_file_create_new();
Expand All @@ -28,6 +26,7 @@ fn main() {
test_symlink();
test_errors();
test_rename();
#[cfg(not(target_os = "freebsd"))]
test_directory();
test_canonicalize();
test_from_raw_os_error();
Expand Down Expand Up @@ -63,6 +62,8 @@ fn test_path_conversion() {
assert!(tmp.is_dir(), "{:?} is not a directory", tmp);
}

// FIXME: lseek64 does not work yet on freebsd 32 bits
#[cfg(not(all(target_os = "freebsd", target_pointer_width = "32")))]
fn test_file() {
let bytes = b"Hello, World!\n";
let path = prepare("miri_test_fs_file.txt");
Expand Down Expand Up @@ -296,7 +297,11 @@ fn test_canonicalize() {
remove_dir_all(&dir_path).unwrap();
}

#[cfg(not(target_os = "freebsd"))] // FIXME: freebsd does not support readdir yet
fn test_directory() {
use std::collections::HashMap;
use std::ffi::OsString;
use std::fs::{read_dir, remove_dir};
let dir_path = prepare_dir("miri_test_fs_dir");
// Creating a directory should succeed.
create_dir(&dir_path).unwrap();
Expand Down

0 comments on commit a04ac72

Please sign in to comment.