Auto merge of #120451 - RalfJung:miri, r=RalfJung
Miri subtree update r? `@ghost`
This commit is contained in:
commit
0ea334ab73
17 changed files with 235 additions and 172 deletions
|
@ -1,8 +1,8 @@
|
|||
name: Tier 2 sysroots
|
||||
|
||||
on: push
|
||||
# schedule:
|
||||
# - cron: '44 4 * * *' # At 4:44 UTC every day.
|
||||
on:
|
||||
schedule:
|
||||
- cron: '44 4 * * *' # At 4:44 UTC every day.
|
||||
|
||||
defaults:
|
||||
run:
|
||||
|
|
|
@ -486,9 +486,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
|||
|
||||
[[package]]
|
||||
name = "measureme"
|
||||
version = "10.1.2"
|
||||
version = "11.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45e381dcdad44c3c435f8052b08c5c4a1449c48ab56f312345eae12d7a693dbe"
|
||||
checksum = "dfa4a40f09af7aa6faef38285402a78847d0d72bf8827006cd2a332e1e6e4a8d"
|
||||
dependencies = [
|
||||
"log",
|
||||
"memmap2",
|
||||
|
|
|
@ -590,6 +590,7 @@ Definite bugs found:
|
|||
* [Incorrect use of `compare_exchange_weak` in `once_cell`](https://github.com/matklad/once_cell/issues/186)
|
||||
* [Dropping with unaligned pointers in `vec::IntoIter`](https://github.com/rust-lang/rust/pull/106084)
|
||||
* [Deallocating with the wrong layout in new specializations for in-place `Iterator::collect`](https://github.com/rust-lang/rust/pull/118460)
|
||||
* [Incorrect offset computation for highly-aligned types in `portable-atomic-util`](https://github.com/taiki-e/portable-atomic/pull/138)
|
||||
|
||||
Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment):
|
||||
|
||||
|
|
|
@ -501,11 +501,10 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
|
|||
// Set missing env vars. We prefer build-time env vars over run-time ones; see
|
||||
// <https://github.com/rust-lang/miri/issues/1661> for the kind of issue that fixes.
|
||||
for (name, val) in info.env {
|
||||
// `CARGO_MAKEFLAGS` contains information about how to reach the
|
||||
// jobserver, but by the time the program is being run, that jobserver
|
||||
// no longer exists. Hence we shouldn't forward this.
|
||||
// FIXME: Miri builds the final crate without a jobserver.
|
||||
// This may be fixed with github.com/rust-lang/cargo/issues/12597.
|
||||
// `CARGO_MAKEFLAGS` contains information about how to reach the jobserver, but by the time
|
||||
// the program is being run, that jobserver no longer exists (cargo only runs the jobserver
|
||||
// for the build portion of `cargo run`/`cargo test`). Hence we shouldn't forward this.
|
||||
// Also see <https://github.com/rust-lang/rust/pull/113730>.
|
||||
if name == "CARGO_MAKEFLAGS" {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
5bcd86d89b2b7b6a490f7e075dd4eb346deb5f98
|
||||
dd2559e08e1530806740931037d6bb83ef956161
|
||||
|
|
|
@ -217,7 +217,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
/// Helper function to get a `windows` constant as a `Scalar`.
|
||||
fn eval_windows(&self, module: &str, name: &str) -> Scalar<Provenance> {
|
||||
self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal","windows", module, name])
|
||||
self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal", "windows", module, name])
|
||||
}
|
||||
|
||||
/// Helper function to get a `windows` constant as a `u32`.
|
||||
|
@ -249,7 +249,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
fn windows_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> {
|
||||
let this = self.eval_context_ref();
|
||||
let ty = this
|
||||
.resolve_path(&["std", "sys", "pal","windows", "c", name], Namespace::TypeNS)
|
||||
.resolve_path(&["std", "sys", "pal", "windows", "c", name], Namespace::TypeNS)
|
||||
.ty(*this.tcx, ty::ParamEnv::reveal_all());
|
||||
this.layout_of(ty).unwrap()
|
||||
}
|
||||
|
@ -270,6 +270,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
bug!("No field named {} in type {}", name, base.layout().ty);
|
||||
}
|
||||
|
||||
/// Search if `base` (which must be a struct or union type) contains the `name` field.
|
||||
fn projectable_has_field<P: Projectable<'tcx, Provenance>>(
|
||||
&self,
|
||||
base: &P,
|
||||
name: &str,
|
||||
) -> bool {
|
||||
let adt = base.layout().ty.ty_adt_def().unwrap();
|
||||
for field in adt.non_enum_variant().fields.iter() {
|
||||
if field.name.as_str() == name {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned,
|
||||
/// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so
|
||||
/// this method is fine for almost all integer types.
|
||||
|
|
|
@ -94,7 +94,6 @@ pub use crate::shims::os_str::EvalContextExt as _;
|
|||
pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _};
|
||||
pub use crate::shims::time::EvalContextExt as _;
|
||||
pub use crate::shims::tls::TlsData;
|
||||
pub use crate::shims::EvalContextExt as _;
|
||||
|
||||
pub use crate::borrow_tracker::stacked_borrows::{
|
||||
EvalContextExt as _, Item, Permission, Stack, Stacks,
|
||||
|
|
|
@ -10,8 +10,8 @@ use std::process;
|
|||
|
||||
use either::Either;
|
||||
use rand::rngs::StdRng;
|
||||
use rand::SeedableRng;
|
||||
use rand::Rng;
|
||||
use rand::SeedableRng;
|
||||
|
||||
use rustc_ast::ast::Mutability;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
|
@ -83,7 +83,8 @@ pub struct FrameExtra<'tcx> {
|
|||
impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// Omitting `timing`, it does not support `Debug`.
|
||||
let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _, salt: _ } = self;
|
||||
let FrameExtra { borrow_tracker, catch_unwind, timing: _, is_user_relevant: _, salt: _ } =
|
||||
self;
|
||||
f.debug_struct("FrameData")
|
||||
.field("borrow_tracker", borrow_tracker)
|
||||
.field("catch_unwind", catch_unwind)
|
||||
|
@ -93,7 +94,8 @@ impl<'tcx> std::fmt::Debug for FrameExtra<'tcx> {
|
|||
|
||||
impl VisitProvenance for FrameExtra<'_> {
|
||||
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
|
||||
let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _, salt: _ } = self;
|
||||
let FrameExtra { catch_unwind, borrow_tracker, timing: _, is_user_relevant: _, salt: _ } =
|
||||
self;
|
||||
|
||||
catch_unwind.visit_provenance(visit);
|
||||
borrow_tracker.visit_provenance(visit);
|
||||
|
@ -710,7 +712,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn add_extern_static(
|
||||
pub(crate) fn add_extern_static(
|
||||
this: &mut MiriInterpCx<'mir, 'tcx>,
|
||||
name: &str,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
|
@ -720,75 +722,6 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
|
|||
this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap();
|
||||
}
|
||||
|
||||
fn alloc_extern_static(
|
||||
this: &mut MiriInterpCx<'mir, 'tcx>,
|
||||
name: &str,
|
||||
val: ImmTy<'tcx, Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?;
|
||||
this.write_immediate(*val, &place)?;
|
||||
Self::add_extern_static(this, name, place.ptr());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets up the "extern statics" for this machine.
|
||||
fn init_extern_statics(this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
|
||||
// "__rust_no_alloc_shim_is_unstable"
|
||||
let val = ImmTy::from_int(0, this.machine.layouts.u8);
|
||||
Self::alloc_extern_static(this, "__rust_no_alloc_shim_is_unstable", val)?;
|
||||
|
||||
match this.tcx.sess.target.os.as_ref() {
|
||||
"linux" => {
|
||||
// "environ"
|
||||
Self::add_extern_static(
|
||||
this,
|
||||
"environ",
|
||||
this.machine.env_vars.environ.as_ref().unwrap().ptr(),
|
||||
);
|
||||
// A couple zero-initialized pointer-sized extern statics.
|
||||
// Most of them are for weak symbols, which we all set to null (indicating that the
|
||||
// symbol is not supported, and triggering fallback code which ends up calling a
|
||||
// syscall that we do support).
|
||||
for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"]
|
||||
{
|
||||
let val = ImmTy::from_int(0, this.machine.layouts.usize);
|
||||
Self::alloc_extern_static(this, name, val)?;
|
||||
}
|
||||
}
|
||||
"freebsd" => {
|
||||
// "environ"
|
||||
Self::add_extern_static(
|
||||
this,
|
||||
"environ",
|
||||
this.machine.env_vars.environ.as_ref().unwrap().ptr(),
|
||||
);
|
||||
}
|
||||
"android" => {
|
||||
// "signal" -- just needs a non-zero pointer value (function does not even get called),
|
||||
// but we arrange for this to be callable anyway (it will then do nothing).
|
||||
let layout = this.machine.layouts.const_raw_ptr;
|
||||
let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str("signal")));
|
||||
let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout);
|
||||
Self::alloc_extern_static(this, "signal", val)?;
|
||||
// A couple zero-initialized pointer-sized extern statics.
|
||||
// Most of them are for weak symbols, which we all set to null (indicating that the
|
||||
// symbol is not supported, and triggering fallback code.)
|
||||
for name in &["bsd_signal"] {
|
||||
let val = ImmTy::from_int(0, this.machine.layouts.usize);
|
||||
Self::alloc_extern_static(this, name, val)?;
|
||||
}
|
||||
}
|
||||
"windows" => {
|
||||
// "_tls_used"
|
||||
// This is some obscure hack that is part of the Windows TLS story. It's a `u8`.
|
||||
let val = ImmTy::from_int(0, this.machine.layouts.u8);
|
||||
Self::alloc_extern_static(this, "_tls_used", val)?;
|
||||
}
|
||||
_ => {} // No "extern statics" supported on this target
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn communicate(&self) -> bool {
|
||||
self.isolated_op == IsolatedOp::Allow
|
||||
}
|
||||
|
@ -1009,7 +942,21 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
|
|||
ret: Option<mir::BasicBlock>,
|
||||
unwind: mir::UnwindAction,
|
||||
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
|
||||
ecx.find_mir_or_eval_fn(instance, abi, args, dest, ret, unwind)
|
||||
// For foreign items, try to see if we can emulate them.
|
||||
if ecx.tcx.is_foreign_item(instance.def_id()) {
|
||||
// An external function call that does not have a MIR body. We either find MIR elsewhere
|
||||
// or emulate its effect.
|
||||
// This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need
|
||||
// to run extra MIR), and Ok(Some(body)) if we found MIR to run for the
|
||||
// foreign function
|
||||
// Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
|
||||
let args = ecx.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
|
||||
let link_name = ecx.item_link_name(instance.def_id());
|
||||
return ecx.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
|
||||
}
|
||||
|
||||
// Otherwise, load the MIR.
|
||||
Ok(Some((ecx.load_mir(instance.def, None)?, instance)))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
|
|
@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
Ok(match bin_op {
|
||||
Eq | Ne | Lt | Le | Gt | Ge => {
|
||||
assert_eq!(left.layout.abi, right.layout.abi); // types an differ, e.g. fn ptrs with different `for`
|
||||
assert_eq!(left.layout.abi, right.layout.abi); // types can differ, e.g. fn ptrs with different `for`
|
||||
let size = this.pointer_size();
|
||||
// Just compare the bits. ScalarPairs are compared lexicographically.
|
||||
// We thus always compare pairs and simply fill scalars up with 0.
|
||||
|
|
79
src/tools/miri/src/shims/extern_static.rs
Normal file
79
src/tools/miri/src/shims/extern_static.rs
Normal file
|
@ -0,0 +1,79 @@
|
|||
//! Provides the `extern static` that this platform expects.
|
||||
|
||||
use crate::*;
|
||||
|
||||
impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
|
||||
fn alloc_extern_static(
|
||||
this: &mut MiriInterpCx<'mir, 'tcx>,
|
||||
name: &str,
|
||||
val: ImmTy<'tcx, Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?;
|
||||
this.write_immediate(*val, &place)?;
|
||||
Self::add_extern_static(this, name, place.ptr());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Zero-initialized pointer-sized extern statics are pretty common.
|
||||
/// Most of them are for weak symbols, which we all set to null (indicating that the
|
||||
/// symbol is not supported, and triggering fallback code which ends up calling a
|
||||
/// syscall that we do support).
|
||||
fn null_ptr_extern_statics(
|
||||
this: &mut MiriInterpCx<'mir, 'tcx>,
|
||||
names: &[&str],
|
||||
) -> InterpResult<'tcx> {
|
||||
for name in names {
|
||||
let val = ImmTy::from_int(0, this.machine.layouts.usize);
|
||||
Self::alloc_extern_static(this, name, val)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets up the "extern statics" for this machine.
|
||||
pub fn init_extern_statics(this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
|
||||
// "__rust_no_alloc_shim_is_unstable"
|
||||
let val = ImmTy::from_int(0, this.machine.layouts.u8);
|
||||
Self::alloc_extern_static(this, "__rust_no_alloc_shim_is_unstable", val)?;
|
||||
|
||||
match this.tcx.sess.target.os.as_ref() {
|
||||
"linux" => {
|
||||
Self::null_ptr_extern_statics(
|
||||
this,
|
||||
&["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"],
|
||||
)?;
|
||||
// "environ"
|
||||
Self::add_extern_static(
|
||||
this,
|
||||
"environ",
|
||||
this.machine.env_vars.environ.as_ref().unwrap().ptr(),
|
||||
);
|
||||
}
|
||||
"freebsd" => {
|
||||
Self::null_ptr_extern_statics(this, &["__cxa_thread_atexit_impl"])?;
|
||||
// "environ"
|
||||
Self::add_extern_static(
|
||||
this,
|
||||
"environ",
|
||||
this.machine.env_vars.environ.as_ref().unwrap().ptr(),
|
||||
);
|
||||
}
|
||||
"android" => {
|
||||
Self::null_ptr_extern_statics(this, &["bsd_signal"])?;
|
||||
// "signal" -- just needs a non-zero pointer value (function does not even get called),
|
||||
// but we arrange for this to call the `signal` function anyway.
|
||||
let layout = this.machine.layouts.const_raw_ptr;
|
||||
let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str("signal")));
|
||||
let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout);
|
||||
Self::alloc_extern_static(this, "signal", val)?;
|
||||
}
|
||||
"windows" => {
|
||||
// "_tls_used"
|
||||
// This is some obscure hack that is part of the Windows TLS story. It's a `u8`.
|
||||
let val = ImmTy::from_int(0, this.machine.layouts.u8);
|
||||
Self::alloc_extern_static(this, "_tls_used", val)?;
|
||||
}
|
||||
_ => {} // No "extern statics" supported on this target
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -148,7 +148,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// ```
|
||||
// Would not be considered UB, or the other way around (`is_val_statically_known(0)`).
|
||||
"is_val_statically_known" => {
|
||||
let [_] = check_arg_count(args)?;
|
||||
let [arg] = check_arg_count(args)?;
|
||||
this.validate_operand(arg)?;
|
||||
let branch: bool = this.machine.rng.get_mut().gen();
|
||||
this.write_scalar(Scalar::from_bool(branch), dest)?;
|
||||
}
|
||||
|
|
|
@ -10,48 +10,8 @@ pub mod windows;
|
|||
mod x86;
|
||||
|
||||
pub mod env;
|
||||
pub mod extern_static;
|
||||
pub mod os_str;
|
||||
pub mod panic;
|
||||
pub mod time;
|
||||
pub mod tls;
|
||||
|
||||
// End module management, begin local code
|
||||
|
||||
use log::trace;
|
||||
|
||||
use rustc_middle::{mir, ty};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use crate::*;
|
||||
|
||||
impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
|
||||
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||
fn find_mir_or_eval_fn(
|
||||
&mut self,
|
||||
instance: ty::Instance<'tcx>,
|
||||
abi: Abi,
|
||||
args: &[FnArg<'tcx, Provenance>],
|
||||
dest: &PlaceTy<'tcx, Provenance>,
|
||||
ret: Option<mir::BasicBlock>,
|
||||
unwind: mir::UnwindAction,
|
||||
) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> {
|
||||
let this = self.eval_context_mut();
|
||||
trace!("eval_fn_call: {:#?}, {:?}", instance, dest);
|
||||
|
||||
// For foreign items, try to see if we can emulate them.
|
||||
if this.tcx.is_foreign_item(instance.def_id()) {
|
||||
// An external function call that does not have a MIR body. We either find MIR elsewhere
|
||||
// or emulate its effect.
|
||||
// This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need
|
||||
// to run extra MIR), and Ok(Some(body)) if we found MIR to run for the
|
||||
// foreign function
|
||||
// Any needed call to `goto_block` will be performed by `emulate_foreign_item`.
|
||||
let args = this.copy_fn_args(args)?; // FIXME: Should `InPlace` arguments be reset to uninit?
|
||||
let link_name = this.item_link_name(instance.def_id());
|
||||
return this.emulate_foreign_item(link_name, abi, &args, dest, ret, unwind);
|
||||
}
|
||||
|
||||
// Otherwise, load the MIR.
|
||||
Ok(Some((this.load_mir(instance.def, None)?, instance)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,6 +155,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.into(), 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_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
|
||||
let whence = this.read_scalar(whence)?.to_i32()?;
|
||||
let result = this.lseek64(fd, offset, whence)?;
|
||||
this.write_scalar(result, dest)?;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
@ -63,6 +64,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
|
||||
}
|
||||
|
||||
// File related shims
|
||||
// For those, we both intercept `func` and `call@FBSD_1.0` symbols cases
|
||||
// since freebsd 12 the former form can be expected.
|
||||
"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)?;
|
||||
|
|
|
@ -813,24 +813,20 @@ 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: i128,
|
||||
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") {
|
||||
SeekFrom::Current(offset)
|
||||
SeekFrom::Current(i64::try_from(offset).unwrap())
|
||||
} else if whence == this.eval_libc_i32("SEEK_END") {
|
||||
SeekFrom::End(offset)
|
||||
SeekFrom::End(i64::try_from(offset).unwrap())
|
||||
} else {
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
|
@ -897,13 +893,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();
|
||||
|
@ -926,13 +925,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();
|
||||
|
@ -953,14 +955,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()?;
|
||||
|
||||
|
@ -1199,7 +1203,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()?
|
||||
|
@ -1371,7 +1375,7 @@ 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>,
|
||||
|
@ -1379,7 +1383,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
) -> 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)?;
|
||||
|
||||
|
@ -1410,7 +1416,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(
|
||||
|
@ -1434,16 +1440,41 @@ 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,
|
||||
)?;
|
||||
// macOS offset field is d_seekoff
|
||||
if this.projectable_has_field(&entry_place, "d_seekoff") {
|
||||
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 if this.projectable_has_field(&entry_place, "d_off") {
|
||||
// freebsd 12 and onwards had added the d_off field
|
||||
this.write_int_fields_named(
|
||||
&[
|
||||
("d_fileno", ino.into()),
|
||||
("d_off", 0),
|
||||
("d_reclen", 0),
|
||||
("d_type", file_type.into()),
|
||||
("d_namlen", file_name_len.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)?;
|
||||
|
|
|
@ -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" => {
|
||||
|
@ -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" => {
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue