Skip to content

Commit ffa8f29

Browse files
committed
freebsd add *stat calls interception support
1 parent d251208 commit ffa8f29

File tree

7 files changed

+100
-46
lines changed

7 files changed

+100
-46
lines changed

ci.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ case $HOST_TARGET in
108108
MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
109109
MIRI_TEST_TARGET=aarch64-apple-darwin run_tests
110110
MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
111-
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
111+
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
112+
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
112113
MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
113114
MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm
114115
MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm

src/shims/unix/foreign_items.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
157157
}
158158
"lseek64" => {
159159
let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
160+
let fd = this.read_scalar(fd)?.to_i32()?;
161+
let offset = this.read_scalar(offset)?.to_i64()?;
162+
let whence = this.read_scalar(whence)?.to_i32()?;
163+
let result = this.lseek64(fd, offset, whence)?;
164+
this.write_scalar(result, dest)?;
165+
}
166+
"lseek" => {
167+
let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
168+
let fd = this.read_scalar(fd)?.to_i32()?;
169+
let offset = this.read_target_isize(offset)?;
170+
let whence = this.read_scalar(whence)?.to_i32()?;
160171
let result = this.lseek64(fd, offset, whence)?;
161172
this.write_scalar(result, dest)?;
162173
}

src/shims/unix/freebsd/foreign_items.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use rustc_target::spec::abi::Abi;
33

44
use crate::*;
55
use shims::foreign_items::EmulateForeignItemResult;
6+
use shims::unix::fs::EvalContextExt as _;
67
use shims::unix::thread::EvalContextExt as _;
78

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

67+
// File related shims
68+
"stat" | "stat@FBSD_1.0" => {
69+
let [path, buf] =
70+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
71+
let result = this.macos_fbsd_stat(path, buf)?;
72+
this.write_scalar(result, dest)?;
73+
}
74+
"lstat" | "lstat@FBSD_1.0" => {
75+
let [path, buf] =
76+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
77+
let result = this.macos_fbsd_lstat(path, buf)?;
78+
this.write_scalar(result, dest)?;
79+
}
80+
"fstat" | "fstat@FBSD_1.0" => {
81+
let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
82+
let result = this.macos_fbsd_fstat(fd, buf)?;
83+
this.write_scalar(result, dest)?;
84+
}
85+
"readdir_r" | "readdir_r@FBSD_1.0" => {
86+
let [dirp, entry, result] =
87+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
88+
let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
89+
this.write_scalar(result, dest)?;
90+
}
91+
6692
// errno
6793
"__error" => {
6894
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;

src/shims/unix/fs.rs

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -827,18 +827,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
827827

828828
fn lseek64(
829829
&mut self,
830-
fd_op: &OpTy<'tcx, Provenance>,
831-
offset_op: &OpTy<'tcx, Provenance>,
832-
whence_op: &OpTy<'tcx, Provenance>,
830+
fd: i32,
831+
offset: i64,
832+
whence: i32,
833833
) -> InterpResult<'tcx, Scalar<Provenance>> {
834834
let this = self.eval_context_mut();
835835

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

838-
let fd = this.read_scalar(fd_op)?.to_i32()?;
839-
let offset = this.read_scalar(offset_op)?.to_i64()?;
840-
let whence = this.read_scalar(whence_op)?.to_i32()?;
841-
842838
let seek_from = if whence == this.eval_libc_i32("SEEK_SET") {
843839
SeekFrom::Start(u64::try_from(offset).unwrap())
844840
} else if whence == this.eval_libc_i32("SEEK_CUR") {
@@ -856,7 +852,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
856852
if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) {
857853
let result = file_descriptor
858854
.seek(communicate, seek_from)?
859-
.map(|offset| i64::try_from(offset).unwrap());
855+
.map(|offset| offset.try_into().unwrap());
860856
this.try_unwrap_io_result(result)?
861857
} else {
862858
this.handle_not_found()?
@@ -911,13 +907,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
911907
this.try_unwrap_io_result(result)
912908
}
913909

914-
fn macos_stat(
910+
fn macos_fbsd_stat(
915911
&mut self,
916912
path_op: &OpTy<'tcx, Provenance>,
917913
buf_op: &OpTy<'tcx, Provenance>,
918914
) -> InterpResult<'tcx, Scalar<Provenance>> {
919915
let this = self.eval_context_mut();
920-
this.assert_target_os("macos", "stat");
916+
917+
if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
918+
panic!("`macos_fbsd_stat` should not be called on {}", this.tcx.sess.target.os);
919+
}
921920

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

942941
// `lstat` is used to get symlink metadata.
943-
fn macos_lstat(
942+
fn macos_fbsd_lstat(
944943
&mut self,
945944
path_op: &OpTy<'tcx, Provenance>,
946945
buf_op: &OpTy<'tcx, Provenance>,
947946
) -> InterpResult<'tcx, Scalar<Provenance>> {
948947
let this = self.eval_context_mut();
949-
this.assert_target_os("macos", "lstat");
948+
949+
if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
950+
panic!("`macos_fbsd_lstat` should not be called on {}", this.tcx.sess.target.os);
951+
}
950952

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

970-
fn macos_fstat(
972+
fn macos_fbsd_fstat(
971973
&mut self,
972974
fd_op: &OpTy<'tcx, Provenance>,
973975
buf_op: &OpTy<'tcx, Provenance>,
974976
) -> InterpResult<'tcx, Scalar<Provenance>> {
975977
let this = self.eval_context_mut();
976978

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

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

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

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

1388-
fn macos_readdir_r(
1392+
fn macos_fbsd_readdir_r(
13891393
&mut self,
13901394
dirp_op: &OpTy<'tcx, Provenance>,
13911395
entry_op: &OpTy<'tcx, Provenance>,
13921396
result_op: &OpTy<'tcx, Provenance>,
13931397
) -> InterpResult<'tcx, Scalar<Provenance>> {
13941398
let this = self.eval_context_mut();
13951399

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

13981404
let dirp = this.read_target_usize(dirp_op)?;
13991405

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

14261432
let entry_place = this.deref_pointer_as(entry_op, this.libc_ty_layout("dirent"))?;
1427-
let name_place = this.project_field(&entry_place, 5)?;
1433+
let name_place = this.project_field_named(&entry_place, "d_name")?;
14281434

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

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

1451-
this.write_int_fields_named(
1452-
&[
1453-
("d_ino", ino.into()),
1454-
("d_seekoff", 0),
1455-
("d_reclen", 0),
1456-
("d_namlen", file_name_len.into()),
1457-
("d_type", file_type.into()),
1458-
],
1459-
&entry_place,
1460-
)?;
1457+
if this.tcx.sess.target.os == "macos" {
1458+
this.write_int_fields_named(
1459+
&[
1460+
("d_ino", ino.into()),
1461+
("d_seekoff", 0),
1462+
("d_reclen", 0),
1463+
("d_namlen", file_name_len.into()),
1464+
("d_type", file_type.into()),
1465+
],
1466+
&entry_place,
1467+
)?;
1468+
} else {
1469+
this.write_int_fields_named(
1470+
&[
1471+
("d_fileno", ino.into()),
1472+
("d_reclen", 0),
1473+
("d_type", file_type.into()),
1474+
("d_namlen", file_name_len.into()),
1475+
],
1476+
&entry_place,
1477+
)?;
1478+
}
14611479

14621480
let result_place = this.deref_pointer(result_op)?;
14631481
this.write_scalar(this.read_scalar(entry_op)?, &result_place)?;

src/shims/unix/macos/foreign_items.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
4040
"stat" | "stat64" | "stat$INODE64" => {
4141
let [path, buf] =
4242
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
43-
let result = this.macos_stat(path, buf)?;
43+
let result = this.macos_fbsd_stat(path, buf)?;
4444
this.write_scalar(result, dest)?;
4545
}
4646
"lstat" | "lstat64" | "lstat$INODE64" => {
4747
let [path, buf] =
4848
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
49-
let result = this.macos_lstat(path, buf)?;
49+
let result = this.macos_fbsd_lstat(path, buf)?;
5050
this.write_scalar(result, dest)?;
5151
}
5252
"fstat" | "fstat64" | "fstat$INODE64" => {
5353
let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
54-
let result = this.macos_fstat(fd, buf)?;
54+
let result = this.macos_fbsd_fstat(fd, buf)?;
5555
this.write_scalar(result, dest)?;
5656
}
5757
"opendir$INODE64" => {
@@ -62,14 +62,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
6262
"readdir_r" | "readdir_r$INODE64" => {
6363
let [dirp, entry, result] =
6464
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
65-
let result = this.macos_readdir_r(dirp, entry, result)?;
66-
this.write_scalar(result, dest)?;
67-
}
68-
"lseek" => {
69-
let [fd, offset, whence] =
70-
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
71-
// macOS is 64bit-only, so this is lseek64
72-
let result = this.lseek64(fd, offset, whence)?;
65+
let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
7366
this.write_scalar(result, dest)?;
7467
}
7568
"realpath$DARWIN_EXTSN" => {

tests/pass-dep/shims/libc-fs-with-isolation.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//@ignore-target-windows: no libc on Windows
2-
//@ignore-target-freebsd: FIXME needs foreign function `stat@FBSD_1.0`
32
//@compile-flags: -Zmiri-isolation-error=warn-nobacktrace
43
//@normalize-stderr-test: "(stat(x)?)" -> "$$STAT"
54

tests/pass/shims/fs.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,18 @@
44
#![feature(io_error_more)]
55
#![feature(io_error_uncategorized)]
66

7-
use std::collections::HashMap;
8-
use std::ffi::OsString;
97
use std::fs::{
10-
canonicalize, create_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, rename,
11-
File, OpenOptions,
8+
canonicalize, create_dir, read_link, remove_dir_all, remove_file, rename, File, OpenOptions,
129
};
13-
use std::io::{Error, ErrorKind, IsTerminal, Read, Result, Seek, SeekFrom, Write};
10+
use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Write};
1411
use std::path::{Path, PathBuf};
1512

1613
#[path = "../../utils/mod.rs"]
1714
mod utils;
1815

1916
fn main() {
2017
test_path_conversion();
18+
#[cfg(not(all(target_os = "freebsd", target_pointer_width = "32")))]
2119
test_file();
2220
test_file_clone();
2321
test_file_create_new();
@@ -28,6 +26,7 @@ fn main() {
2826
test_symlink();
2927
test_errors();
3028
test_rename();
29+
#[cfg(not(target_os = "freebsd"))]
3130
test_directory();
3231
test_canonicalize();
3332
test_from_raw_os_error();
@@ -63,7 +62,10 @@ fn test_path_conversion() {
6362
assert!(tmp.is_dir(), "{:?} is not a directory", tmp);
6463
}
6564

65+
// FIXME: lseek64 does not work yet on freebsd 32 bits
66+
#[cfg(not(all(target_os = "freebsd", target_pointer_width = "32")))]
6667
fn test_file() {
68+
ise std::io::Terminal;
6769
let bytes = b"Hello, World!\n";
6870
let path = prepare("miri_test_fs_file.txt");
6971

@@ -296,7 +298,11 @@ fn test_canonicalize() {
296298
remove_dir_all(&dir_path).unwrap();
297299
}
298300

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

0 commit comments

Comments
 (0)