Skip to content

Commit 71f8f49

Browse files
committed
Auto merge of #3181 - devnexen:stat_calls_fbsd, r=RalfJung
freebsd add *stat calls interception support
2 parents 0186c24 + 8302e25 commit 71f8f49

File tree

6 files changed

+118
-41
lines changed

6 files changed

+118
-41
lines changed

src/tools/miri/src/helpers.rs

+15
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
270270
bug!("No field named {} in type {}", name, base.layout().ty);
271271
}
272272

273+
/// Search if `base` (which must be a struct or union type) contains the `name` field.
274+
fn projectable_has_field<P: Projectable<'tcx, Provenance>>(
275+
&self,
276+
base: &P,
277+
name: &str,
278+
) -> bool {
279+
let adt = base.layout().ty.ty_adt_def().unwrap();
280+
for field in adt.non_enum_variant().fields.iter() {
281+
if field.name.as_str() == name {
282+
return true;
283+
}
284+
}
285+
false
286+
}
287+
273288
/// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned,
274289
/// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so
275290
/// this method is fine for almost all integer types.

src/tools/miri/src/shims/unix/foreign_items.rs

+11
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
155155
}
156156
"lseek64" => {
157157
let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
158+
let fd = this.read_scalar(fd)?.to_i32()?;
159+
let offset = this.read_scalar(offset)?.to_i64()?;
160+
let whence = this.read_scalar(whence)?.to_i32()?;
161+
let result = this.lseek64(fd, offset.into(), whence)?;
162+
this.write_scalar(result, dest)?;
163+
}
164+
"lseek" => {
165+
let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
166+
let fd = this.read_scalar(fd)?.to_i32()?;
167+
let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
168+
let whence = this.read_scalar(whence)?.to_i32()?;
158169
let result = this.lseek64(fd, offset, whence)?;
159170
this.write_scalar(result, dest)?;
160171
}

src/tools/miri/src/shims/unix/freebsd/foreign_items.rs

+28
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,33 @@ 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+
// For those, we both intercept `func` and `call@FBSD_1.0` symbols cases
69+
// since freebsd 12 the former form can be expected.
70+
"stat" | "stat@FBSD_1.0" => {
71+
let [path, buf] =
72+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
73+
let result = this.macos_fbsd_stat(path, buf)?;
74+
this.write_scalar(result, dest)?;
75+
}
76+
"lstat" | "lstat@FBSD_1.0" => {
77+
let [path, buf] =
78+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
79+
let result = this.macos_fbsd_lstat(path, buf)?;
80+
this.write_scalar(result, dest)?;
81+
}
82+
"fstat" | "fstat@FBSD_1.0" => {
83+
let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
84+
let result = this.macos_fbsd_fstat(fd, buf)?;
85+
this.write_scalar(result, dest)?;
86+
}
87+
"readdir_r" | "readdir_r@FBSD_1.0" => {
88+
let [dirp, entry, result] =
89+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
90+
let result = this.macos_fbsd_readdir_r(dirp, entry, result)?;
91+
this.write_scalar(result, dest)?;
92+
}
93+
6694
// errno
6795
"__error" => {
6896
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;

src/tools/miri/src/shims/unix/fs.rs

+60-29
Original file line numberDiff line numberDiff line change
@@ -813,24 +813,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
813813

814814
fn lseek64(
815815
&mut self,
816-
fd_op: &OpTy<'tcx, Provenance>,
817-
offset_op: &OpTy<'tcx, Provenance>,
818-
whence_op: &OpTy<'tcx, Provenance>,
816+
fd: i32,
817+
offset: i128,
818+
whence: i32,
819819
) -> InterpResult<'tcx, Scalar<Provenance>> {
820820
let this = self.eval_context_mut();
821821

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

824-
let fd = this.read_scalar(fd_op)?.to_i32()?;
825-
let offset = this.read_scalar(offset_op)?.to_i64()?;
826-
let whence = this.read_scalar(whence_op)?.to_i32()?;
827-
828824
let seek_from = if whence == this.eval_libc_i32("SEEK_SET") {
829825
SeekFrom::Start(u64::try_from(offset).unwrap())
830826
} else if whence == this.eval_libc_i32("SEEK_CUR") {
831-
SeekFrom::Current(offset)
827+
SeekFrom::Current(i64::try_from(offset).unwrap())
832828
} else if whence == this.eval_libc_i32("SEEK_END") {
833-
SeekFrom::End(offset)
829+
SeekFrom::End(i64::try_from(offset).unwrap())
834830
} else {
835831
let einval = this.eval_libc("EINVAL");
836832
this.set_last_error(einval)?;
@@ -897,13 +893,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
897893
this.try_unwrap_io_result(result)
898894
}
899895

900-
fn macos_stat(
896+
fn macos_fbsd_stat(
901897
&mut self,
902898
path_op: &OpTy<'tcx, Provenance>,
903899
buf_op: &OpTy<'tcx, Provenance>,
904900
) -> InterpResult<'tcx, Scalar<Provenance>> {
905901
let this = self.eval_context_mut();
906-
this.assert_target_os("macos", "stat");
902+
903+
if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
904+
panic!("`macos_fbsd_stat` should not be called on {}", this.tcx.sess.target.os);
905+
}
907906

908907
let path_scalar = this.read_pointer(path_op)?;
909908
let path = this.read_path_from_c_str(path_scalar)?.into_owned();
@@ -926,13 +925,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
926925
}
927926

928927
// `lstat` is used to get symlink metadata.
929-
fn macos_lstat(
928+
fn macos_fbsd_lstat(
930929
&mut self,
931930
path_op: &OpTy<'tcx, Provenance>,
932931
buf_op: &OpTy<'tcx, Provenance>,
933932
) -> InterpResult<'tcx, Scalar<Provenance>> {
934933
let this = self.eval_context_mut();
935-
this.assert_target_os("macos", "lstat");
934+
935+
if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
936+
panic!("`macos_fbsd_lstat` should not be called on {}", this.tcx.sess.target.os);
937+
}
936938

937939
let path_scalar = this.read_pointer(path_op)?;
938940
let path = this.read_path_from_c_str(path_scalar)?.into_owned();
@@ -953,14 +955,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
953955
Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
954956
}
955957

956-
fn macos_fstat(
958+
fn macos_fbsd_fstat(
957959
&mut self,
958960
fd_op: &OpTy<'tcx, Provenance>,
959961
buf_op: &OpTy<'tcx, Provenance>,
960962
) -> InterpResult<'tcx, Scalar<Provenance>> {
961963
let this = self.eval_context_mut();
962964

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

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

@@ -1199,7 +1203,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
11991203
let this = self.eval_context_mut();
12001204

12011205
#[cfg_attr(not(unix), allow(unused_variables))]
1202-
let mode = if this.tcx.sess.target.os == "macos" {
1206+
let mode = if matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") {
12031207
u32::from(this.read_scalar(mode_op)?.to_u16()?)
12041208
} else {
12051209
this.read_scalar(mode_op)?.to_u32()?
@@ -1371,15 +1375,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
13711375
Ok(Scalar::from_maybe_pointer(entry, this))
13721376
}
13731377

1374-
fn macos_readdir_r(
1378+
fn macos_fbsd_readdir_r(
13751379
&mut self,
13761380
dirp_op: &OpTy<'tcx, Provenance>,
13771381
entry_op: &OpTy<'tcx, Provenance>,
13781382
result_op: &OpTy<'tcx, Provenance>,
13791383
) -> InterpResult<'tcx, Scalar<Provenance>> {
13801384
let this = self.eval_context_mut();
13811385

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

13841390
let dirp = this.read_target_usize(dirp_op)?;
13851391

@@ -1410,7 +1416,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
14101416
// }
14111417

14121418
let entry_place = this.deref_pointer_as(entry_op, this.libc_ty_layout("dirent"))?;
1413-
let name_place = this.project_field(&entry_place, 5)?;
1419+
let name_place = this.project_field_named(&entry_place, "d_name")?;
14141420

14151421
let file_name = dir_entry.file_name(); // not a Path as there are no separators!
14161422
let (name_fits, file_name_buf_len) = this.write_os_str_to_c_str(
@@ -1434,16 +1440,41 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
14341440

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

1437-
this.write_int_fields_named(
1438-
&[
1439-
("d_ino", ino.into()),
1440-
("d_seekoff", 0),
1441-
("d_reclen", 0),
1442-
("d_namlen", file_name_len.into()),
1443-
("d_type", file_type.into()),
1444-
],
1445-
&entry_place,
1446-
)?;
1443+
// macOS offset field is d_seekoff
1444+
if this.projectable_has_field(&entry_place, "d_seekoff") {
1445+
this.write_int_fields_named(
1446+
&[
1447+
("d_ino", ino.into()),
1448+
("d_seekoff", 0),
1449+
("d_reclen", 0),
1450+
("d_namlen", file_name_len.into()),
1451+
("d_type", file_type.into()),
1452+
],
1453+
&entry_place,
1454+
)?;
1455+
} else if this.projectable_has_field(&entry_place, "d_off") {
1456+
// freebsd 12 and onwards had added the d_off field
1457+
this.write_int_fields_named(
1458+
&[
1459+
("d_fileno", ino.into()),
1460+
("d_off", 0),
1461+
("d_reclen", 0),
1462+
("d_type", file_type.into()),
1463+
("d_namlen", file_name_len.into()),
1464+
],
1465+
&entry_place,
1466+
)?;
1467+
} else {
1468+
this.write_int_fields_named(
1469+
&[
1470+
("d_fileno", ino.into()),
1471+
("d_reclen", 0),
1472+
("d_type", file_type.into()),
1473+
("d_namlen", file_name_len.into()),
1474+
],
1475+
&entry_place,
1476+
)?;
1477+
}
14471478

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

src/tools/miri/src/shims/unix/macos/foreign_items.rs

+4-11
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" => {

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

-1
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

0 commit comments

Comments
 (0)