Renamed this arguments to ecx
This commit is contained in:
parent
e2b7027661
commit
e43a5c0ac5
12 changed files with 382 additions and 383 deletions
|
|
@ -1009,7 +1009,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let this = self.eval_context_ref();
|
||||
|
||||
fn float_to_int_inner<'tcx, F: rustc_apfloat::Float>(
|
||||
this: &MiriInterpCx<'tcx>,
|
||||
ecx: &MiriInterpCx<'tcx>,
|
||||
src: F,
|
||||
cast_to: TyAndLayout<'tcx>,
|
||||
round: rustc_apfloat::Round,
|
||||
|
|
@ -1029,7 +1029,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
// Nothing else
|
||||
_ =>
|
||||
span_bug!(
|
||||
this.cur_span(),
|
||||
ecx.cur_span(),
|
||||
"attempted float-to-int conversion with non-int output type {}",
|
||||
cast_to.ty,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -730,20 +730,20 @@ impl<'tcx> MiriMachine<'tcx> {
|
|||
}
|
||||
|
||||
pub(crate) fn late_init(
|
||||
this: &mut MiriInterpCx<'tcx>,
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
config: &MiriConfig,
|
||||
on_main_stack_empty: StackEmptyCallback<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
EnvVars::init(this, config)?;
|
||||
MiriMachine::init_extern_statics(this)?;
|
||||
ThreadManager::init(this, on_main_stack_empty);
|
||||
EnvVars::init(ecx, config)?;
|
||||
MiriMachine::init_extern_statics(ecx)?;
|
||||
ThreadManager::init(ecx, on_main_stack_empty);
|
||||
interp_ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn add_extern_static(this: &mut MiriInterpCx<'tcx>, name: &str, ptr: Pointer) {
|
||||
pub(crate) fn add_extern_static(ecx: &mut MiriInterpCx<'tcx>, name: &str, ptr: Pointer) {
|
||||
// This got just allocated, so there definitely is a pointer here.
|
||||
let ptr = ptr.into_pointer_or_addr().unwrap();
|
||||
this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap();
|
||||
ecx.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap();
|
||||
}
|
||||
|
||||
pub(crate) fn communicate(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -195,10 +195,10 @@ impl LiveAllocs<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn remove_unreachable_tags<'tcx>(this: &mut MiriInterpCx<'tcx>, tags: FxHashSet<BorTag>) {
|
||||
fn remove_unreachable_tags<'tcx>(ecx: &mut MiriInterpCx<'tcx>, tags: FxHashSet<BorTag>) {
|
||||
// Avoid iterating all allocations if there's no borrow tracker anyway.
|
||||
if this.machine.borrow_tracker.is_some() {
|
||||
this.memory.alloc_map().iter(|it| {
|
||||
if ecx.machine.borrow_tracker.is_some() {
|
||||
ecx.memory.alloc_map().iter(|it| {
|
||||
for (_id, (_kind, alloc)) in it {
|
||||
alloc.extra.borrow_tracker.as_ref().unwrap().remove_unreachable_tags(&tags);
|
||||
}
|
||||
|
|
@ -206,16 +206,16 @@ fn remove_unreachable_tags<'tcx>(this: &mut MiriInterpCx<'tcx>, tags: FxHashSet<
|
|||
}
|
||||
}
|
||||
|
||||
fn remove_unreachable_allocs<'tcx>(this: &mut MiriInterpCx<'tcx>, allocs: FxHashSet<AllocId>) {
|
||||
let allocs = LiveAllocs { ecx: this, collected: allocs };
|
||||
this.machine.allocation_spans.borrow_mut().retain(|id, _| allocs.is_live(*id));
|
||||
this.machine.symbolic_alignment.borrow_mut().retain(|id, _| allocs.is_live(*id));
|
||||
this.machine.alloc_addresses.borrow_mut().remove_unreachable_allocs(&allocs);
|
||||
if let Some(borrow_tracker) = &this.machine.borrow_tracker {
|
||||
fn remove_unreachable_allocs<'tcx>(ecx: &mut MiriInterpCx<'tcx>, allocs: FxHashSet<AllocId>) {
|
||||
let allocs = LiveAllocs { ecx, collected: allocs };
|
||||
ecx.machine.allocation_spans.borrow_mut().retain(|id, _| allocs.is_live(*id));
|
||||
ecx.machine.symbolic_alignment.borrow_mut().retain(|id, _| allocs.is_live(*id));
|
||||
ecx.machine.alloc_addresses.borrow_mut().remove_unreachable_allocs(&allocs);
|
||||
if let Some(borrow_tracker) = &ecx.machine.borrow_tracker {
|
||||
borrow_tracker.borrow_mut().remove_unreachable_allocs(&allocs);
|
||||
}
|
||||
// Clean up core (non-Miri-specific) state.
|
||||
this.remove_unreachable_allocs(&allocs.collected);
|
||||
ecx.remove_unreachable_allocs(&allocs.collected);
|
||||
}
|
||||
|
||||
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
|
||||
|
|
|
|||
|
|
@ -496,14 +496,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
// Rust allocation
|
||||
"__rust_alloc" | "miri_alloc" => {
|
||||
let default = |this: &mut MiriInterpCx<'tcx>| {
|
||||
let default = |ecx: &mut MiriInterpCx<'tcx>| {
|
||||
// Only call `check_shim` when `#[global_allocator]` isn't used. When that
|
||||
// macro is used, we act like no shim exists, so that the exported function can run.
|
||||
let [size, align] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
|
||||
let size = this.read_target_usize(size)?;
|
||||
let align = this.read_target_usize(align)?;
|
||||
let [size, align] = ecx.check_shim(abi, ExternAbi::Rust, link_name, args)?;
|
||||
let size = ecx.read_target_usize(size)?;
|
||||
let align = ecx.read_target_usize(align)?;
|
||||
|
||||
this.check_rustc_alloc_request(size, align)?;
|
||||
ecx.check_rustc_alloc_request(size, align)?;
|
||||
|
||||
let memory_kind = match link_name.as_str() {
|
||||
"__rust_alloc" => MiriMemoryKind::Rust,
|
||||
|
|
@ -511,13 +511,13 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let ptr = this.allocate_ptr(
|
||||
let ptr = ecx.allocate_ptr(
|
||||
Size::from_bytes(size),
|
||||
Align::from_bytes(align).unwrap(),
|
||||
memory_kind.into(),
|
||||
)?;
|
||||
|
||||
this.write_pointer(ptr, dest)
|
||||
ecx.write_pointer(ptr, dest)
|
||||
};
|
||||
|
||||
match link_name.as_str() {
|
||||
|
|
@ -555,14 +555,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
});
|
||||
}
|
||||
"__rust_dealloc" | "miri_dealloc" => {
|
||||
let default = |this: &mut MiriInterpCx<'tcx>| {
|
||||
let default = |ecx: &mut MiriInterpCx<'tcx>| {
|
||||
// See the comment for `__rust_alloc` why `check_shim` is only called in the
|
||||
// default case.
|
||||
let [ptr, old_size, align] =
|
||||
this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
|
||||
let ptr = this.read_pointer(ptr)?;
|
||||
let old_size = this.read_target_usize(old_size)?;
|
||||
let align = this.read_target_usize(align)?;
|
||||
ecx.check_shim(abi, ExternAbi::Rust, link_name, args)?;
|
||||
let ptr = ecx.read_pointer(ptr)?;
|
||||
let old_size = ecx.read_target_usize(old_size)?;
|
||||
let align = ecx.read_target_usize(align)?;
|
||||
|
||||
let memory_kind = match link_name.as_str() {
|
||||
"__rust_dealloc" => MiriMemoryKind::Rust,
|
||||
|
|
@ -571,7 +571,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
};
|
||||
|
||||
// No need to check old_size/align; we anyway check that they match the allocation.
|
||||
this.deallocate_ptr(
|
||||
ecx.deallocate_ptr(
|
||||
ptr,
|
||||
Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())),
|
||||
memory_kind.into(),
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use crate::*;
|
|||
const TASK_COMM_LEN: usize = 16;
|
||||
|
||||
pub fn prctl<'tcx>(
|
||||
this: &mut MiriInterpCx<'tcx>,
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
link_name: Symbol,
|
||||
abi: ExternAbi,
|
||||
args: &[OpTy<'tcx>],
|
||||
|
|
@ -16,41 +16,41 @@ pub fn prctl<'tcx>(
|
|||
) -> InterpResult<'tcx> {
|
||||
// We do not use `check_shim` here because `prctl` is variadic. The argument
|
||||
// count is checked bellow.
|
||||
this.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
|
||||
ecx.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
|
||||
|
||||
// FIXME: Use constants once https://github.com/rust-lang/libc/pull/3941 backported to the 0.2 branch.
|
||||
let pr_set_name = 15;
|
||||
let pr_get_name = 16;
|
||||
|
||||
let [op] = check_min_arg_count("prctl", args)?;
|
||||
let res = match this.read_scalar(op)?.to_i32()? {
|
||||
let res = match ecx.read_scalar(op)?.to_i32()? {
|
||||
op if op == pr_set_name => {
|
||||
let [_, name] = check_min_arg_count("prctl(PR_SET_NAME, ...)", args)?;
|
||||
let name = this.read_scalar(name)?;
|
||||
let thread = this.pthread_self()?;
|
||||
let name = ecx.read_scalar(name)?;
|
||||
let thread = ecx.pthread_self()?;
|
||||
// The Linux kernel silently truncates long names.
|
||||
// https://www.man7.org/linux/man-pages/man2/PR_SET_NAME.2const.html
|
||||
let res =
|
||||
this.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?;
|
||||
ecx.pthread_setname_np(thread, name, TASK_COMM_LEN, /* truncate */ true)?;
|
||||
assert_eq!(res, ThreadNameResult::Ok);
|
||||
Scalar::from_u32(0)
|
||||
}
|
||||
op if op == pr_get_name => {
|
||||
let [_, name] = check_min_arg_count("prctl(PR_GET_NAME, ...)", args)?;
|
||||
let name = this.read_scalar(name)?;
|
||||
let thread = this.pthread_self()?;
|
||||
let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, this);
|
||||
this.check_ptr_access(
|
||||
name.to_pointer(this)?,
|
||||
let name = ecx.read_scalar(name)?;
|
||||
let thread = ecx.pthread_self()?;
|
||||
let len = Scalar::from_target_usize(TASK_COMM_LEN as u64, ecx);
|
||||
ecx.check_ptr_access(
|
||||
name.to_pointer(ecx)?,
|
||||
Size::from_bytes(TASK_COMM_LEN),
|
||||
CheckInAllocMsg::MemoryAccessTest,
|
||||
)?;
|
||||
let res = this.pthread_getname_np(thread, name, len, /* truncate*/ false)?;
|
||||
let res = ecx.pthread_getname_np(thread, name, len, /* truncate*/ false)?;
|
||||
assert_eq!(res, ThreadNameResult::Ok);
|
||||
Scalar::from_u32(0)
|
||||
}
|
||||
op => throw_unsup_format!("Miri does not support `prctl` syscall with op={}", op),
|
||||
};
|
||||
this.write_scalar(res, dest)?;
|
||||
ecx.write_scalar(res, dest)?;
|
||||
interp_ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ struct LinuxFutex {
|
|||
/// Implementation of the SYS_futex syscall.
|
||||
/// `args` is the arguments *including* the syscall number.
|
||||
pub fn futex<'tcx>(
|
||||
this: &mut MiriInterpCx<'tcx>,
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
args: &[OpTy<'tcx>],
|
||||
dest: &MPlaceTy<'tcx>,
|
||||
) -> InterpResult<'tcx> {
|
||||
|
|
@ -26,19 +26,19 @@ pub fn futex<'tcx>(
|
|||
// The first three arguments (after the syscall number itself) are the same to all futex operations:
|
||||
// (int *addr, int op, int val).
|
||||
// We checked above that these definitely exist.
|
||||
let addr = this.read_pointer(addr)?;
|
||||
let op = this.read_scalar(op)?.to_i32()?;
|
||||
let val = this.read_scalar(val)?.to_i32()?;
|
||||
let addr = ecx.read_pointer(addr)?;
|
||||
let op = ecx.read_scalar(op)?.to_i32()?;
|
||||
let val = ecx.read_scalar(val)?.to_i32()?;
|
||||
|
||||
// This is a vararg function so we have to bring our own type for this pointer.
|
||||
let addr = this.ptr_to_mplace(addr, this.machine.layouts.i32);
|
||||
let addr = ecx.ptr_to_mplace(addr, ecx.machine.layouts.i32);
|
||||
|
||||
let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG");
|
||||
let futex_wait = this.eval_libc_i32("FUTEX_WAIT");
|
||||
let futex_wait_bitset = this.eval_libc_i32("FUTEX_WAIT_BITSET");
|
||||
let futex_wake = this.eval_libc_i32("FUTEX_WAKE");
|
||||
let futex_wake_bitset = this.eval_libc_i32("FUTEX_WAKE_BITSET");
|
||||
let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME");
|
||||
let futex_private = ecx.eval_libc_i32("FUTEX_PRIVATE_FLAG");
|
||||
let futex_wait = ecx.eval_libc_i32("FUTEX_WAIT");
|
||||
let futex_wait_bitset = ecx.eval_libc_i32("FUTEX_WAIT_BITSET");
|
||||
let futex_wake = ecx.eval_libc_i32("FUTEX_WAKE");
|
||||
let futex_wake_bitset = ecx.eval_libc_i32("FUTEX_WAKE_BITSET");
|
||||
let futex_realtime = ecx.eval_libc_i32("FUTEX_CLOCK_REALTIME");
|
||||
|
||||
// FUTEX_PRIVATE enables an optimization that stops it from working across processes.
|
||||
// Miri doesn't support that anyway, so we ignore that flag.
|
||||
|
|
@ -57,9 +57,9 @@ pub fn futex<'tcx>(
|
|||
let (timeout, bitset) = if wait_bitset {
|
||||
let [_, _, _, _, timeout, uaddr2, bitset] =
|
||||
check_min_arg_count("`syscall(SYS_futex, FUTEX_WAIT_BITSET, ...)`", args)?;
|
||||
let _timeout = this.read_pointer(timeout)?;
|
||||
let _uaddr2 = this.read_pointer(uaddr2)?;
|
||||
(timeout, this.read_scalar(bitset)?.to_u32()?)
|
||||
let _timeout = ecx.read_pointer(timeout)?;
|
||||
let _uaddr2 = ecx.read_pointer(uaddr2)?;
|
||||
(timeout, ecx.read_scalar(bitset)?.to_u32()?)
|
||||
} else {
|
||||
let [_, _, _, _, timeout] =
|
||||
check_min_arg_count("`syscall(SYS_futex, FUTEX_WAIT, ...)`", args)?;
|
||||
|
|
@ -67,21 +67,21 @@ pub fn futex<'tcx>(
|
|||
};
|
||||
|
||||
if bitset == 0 {
|
||||
return this.set_last_error_and_return(LibcError("EINVAL"), dest);
|
||||
return ecx.set_last_error_and_return(LibcError("EINVAL"), dest);
|
||||
}
|
||||
|
||||
let timeout = this.deref_pointer_as(timeout, this.libc_ty_layout("timespec"))?;
|
||||
let timeout = if this.ptr_is_null(timeout.ptr())? {
|
||||
let timeout = ecx.deref_pointer_as(timeout, ecx.libc_ty_layout("timespec"))?;
|
||||
let timeout = if ecx.ptr_is_null(timeout.ptr())? {
|
||||
None
|
||||
} else {
|
||||
let duration = match this.read_timespec(&timeout)? {
|
||||
let duration = match ecx.read_timespec(&timeout)? {
|
||||
Some(duration) => duration,
|
||||
None => {
|
||||
return this.set_last_error_and_return(LibcError("EINVAL"), dest);
|
||||
return ecx.set_last_error_and_return(LibcError("EINVAL"), dest);
|
||||
}
|
||||
};
|
||||
let timeout_clock = if op & futex_realtime == futex_realtime {
|
||||
this.check_no_isolation(
|
||||
ecx.check_no_isolation(
|
||||
"`futex` syscall with `op=FUTEX_WAIT` and non-null timeout with `FUTEX_CLOCK_REALTIME`",
|
||||
)?;
|
||||
TimeoutClock::RealTime
|
||||
|
|
@ -139,36 +139,36 @@ pub fn futex<'tcx>(
|
|||
//
|
||||
// Thankfully, preemptions cannot happen inside a Miri shim, so we do not need to
|
||||
// do anything special to guarantee fence-load-comparison atomicity.
|
||||
this.atomic_fence(AtomicFenceOrd::SeqCst)?;
|
||||
ecx.atomic_fence(AtomicFenceOrd::SeqCst)?;
|
||||
// Read an `i32` through the pointer, regardless of any wrapper types.
|
||||
// It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`.
|
||||
// We do an acquire read -- it only seems reasonable that if we observe a value here, we
|
||||
// actually establish an ordering with that value.
|
||||
let futex_val = this.read_scalar_atomic(&addr, AtomicReadOrd::Acquire)?.to_i32()?;
|
||||
let futex_val = ecx.read_scalar_atomic(&addr, AtomicReadOrd::Acquire)?.to_i32()?;
|
||||
if val == futex_val {
|
||||
// The value still matches, so we block the thread and make it wait for FUTEX_WAKE.
|
||||
|
||||
// This cannot fail since we already did an atomic acquire read on that pointer.
|
||||
// Acquire reads are only allowed on mutable memory.
|
||||
let futex_ref = this
|
||||
let futex_ref = ecx
|
||||
.get_sync_or_init(addr.ptr(), |_| LinuxFutex { futex: Default::default() })
|
||||
.unwrap()
|
||||
.futex
|
||||
.clone();
|
||||
|
||||
this.futex_wait(
|
||||
ecx.futex_wait(
|
||||
futex_ref,
|
||||
bitset,
|
||||
timeout,
|
||||
Scalar::from_target_isize(0, this), // retval_succ
|
||||
Scalar::from_target_isize(-1, this), // retval_timeout
|
||||
Scalar::from_target_isize(0, ecx), // retval_succ
|
||||
Scalar::from_target_isize(-1, ecx), // retval_timeout
|
||||
dest.clone(),
|
||||
LibcError("ETIMEDOUT"), // errno_timeout
|
||||
);
|
||||
} else {
|
||||
// The futex value doesn't match the expected value, so we return failure
|
||||
// right away without sleeping: -1 and errno set to EAGAIN.
|
||||
return this.set_last_error_and_return(LibcError("EAGAIN"), dest);
|
||||
return ecx.set_last_error_and_return(LibcError("EAGAIN"), dest);
|
||||
}
|
||||
}
|
||||
// FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val)
|
||||
|
|
@ -179,42 +179,42 @@ pub fn futex<'tcx>(
|
|||
// Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up.
|
||||
op if op == futex_wake || op == futex_wake_bitset => {
|
||||
let Some(futex_ref) =
|
||||
this.get_sync_or_init(addr.ptr(), |_| LinuxFutex { futex: Default::default() })
|
||||
ecx.get_sync_or_init(addr.ptr(), |_| LinuxFutex { futex: Default::default() })
|
||||
else {
|
||||
// No AllocId, or no live allocation at that AllocId.
|
||||
// Return an error code. (That seems nicer than silently doing something non-intuitive.)
|
||||
// This means that if an address gets reused by a new allocation,
|
||||
// we'll use an independent futex queue for this... that seems acceptable.
|
||||
return this.set_last_error_and_return(LibcError("EFAULT"), dest);
|
||||
return ecx.set_last_error_and_return(LibcError("EFAULT"), dest);
|
||||
};
|
||||
let futex_ref = futex_ref.futex.clone();
|
||||
|
||||
let bitset = if op == futex_wake_bitset {
|
||||
let [_, _, _, _, timeout, uaddr2, bitset] =
|
||||
check_min_arg_count("`syscall(SYS_futex, FUTEX_WAKE_BITSET, ...)`", args)?;
|
||||
let _timeout = this.read_pointer(timeout)?;
|
||||
let _uaddr2 = this.read_pointer(uaddr2)?;
|
||||
this.read_scalar(bitset)?.to_u32()?
|
||||
let _timeout = ecx.read_pointer(timeout)?;
|
||||
let _uaddr2 = ecx.read_pointer(uaddr2)?;
|
||||
ecx.read_scalar(bitset)?.to_u32()?
|
||||
} else {
|
||||
u32::MAX
|
||||
};
|
||||
if bitset == 0 {
|
||||
return this.set_last_error_and_return(LibcError("EINVAL"), dest);
|
||||
return ecx.set_last_error_and_return(LibcError("EINVAL"), dest);
|
||||
}
|
||||
// Together with the SeqCst fence in futex_wait, this makes sure that futex_wait
|
||||
// will see the latest value on addr which could be changed by our caller
|
||||
// before doing the syscall.
|
||||
this.atomic_fence(AtomicFenceOrd::SeqCst)?;
|
||||
ecx.atomic_fence(AtomicFenceOrd::SeqCst)?;
|
||||
let mut n = 0;
|
||||
#[expect(clippy::arithmetic_side_effects)]
|
||||
for _ in 0..val {
|
||||
if this.futex_wake(&futex_ref, bitset)? {
|
||||
if ecx.futex_wake(&futex_ref, bitset)? {
|
||||
n += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.write_scalar(Scalar::from_target_isize(n, this), dest)?;
|
||||
ecx.write_scalar(Scalar::from_target_isize(n, ecx), dest)?;
|
||||
}
|
||||
op => throw_unsup_format!("Miri does not support `futex` syscall with op={}", op),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use crate::shims::unix::linux::sync::futex;
|
|||
use crate::*;
|
||||
|
||||
pub fn syscall<'tcx>(
|
||||
this: &mut MiriInterpCx<'tcx>,
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
link_name: Symbol,
|
||||
abi: ExternAbi,
|
||||
args: &[OpTy<'tcx>],
|
||||
|
|
@ -15,18 +15,18 @@ pub fn syscall<'tcx>(
|
|||
) -> InterpResult<'tcx> {
|
||||
// We do not use `check_shim` here because `syscall` is variadic. The argument
|
||||
// count is checked bellow.
|
||||
this.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
|
||||
ecx.check_abi_and_shim_symbol_clash(abi, ExternAbi::C { unwind: false }, link_name)?;
|
||||
// The syscall variadic function is legal to call with more arguments than needed,
|
||||
// extra arguments are simply ignored. The important check is that when we use an
|
||||
// argument, we have to also check all arguments *before* it to ensure that they
|
||||
// have the right type.
|
||||
|
||||
let sys_getrandom = this.eval_libc("SYS_getrandom").to_target_usize(this)?;
|
||||
let sys_futex = this.eval_libc("SYS_futex").to_target_usize(this)?;
|
||||
let sys_eventfd2 = this.eval_libc("SYS_eventfd2").to_target_usize(this)?;
|
||||
let sys_getrandom = ecx.eval_libc("SYS_getrandom").to_target_usize(ecx)?;
|
||||
let sys_futex = ecx.eval_libc("SYS_futex").to_target_usize(ecx)?;
|
||||
let sys_eventfd2 = ecx.eval_libc("SYS_eventfd2").to_target_usize(ecx)?;
|
||||
|
||||
let [op] = check_min_arg_count("syscall", args)?;
|
||||
match this.read_target_usize(op)? {
|
||||
match ecx.read_target_usize(op)? {
|
||||
// `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)`
|
||||
// is called if a `HashMap` is created the regular way (e.g. HashMap<K, V>).
|
||||
num if num == sys_getrandom => {
|
||||
|
|
@ -34,25 +34,25 @@ pub fn syscall<'tcx>(
|
|||
// The first argument is the syscall id, so skip over it.
|
||||
let [_, ptr, len, flags] = check_min_arg_count("syscall(SYS_getrandom, ...)", args)?;
|
||||
|
||||
let ptr = this.read_pointer(ptr)?;
|
||||
let len = this.read_target_usize(len)?;
|
||||
let ptr = ecx.read_pointer(ptr)?;
|
||||
let len = ecx.read_target_usize(len)?;
|
||||
// The only supported flags are GRND_RANDOM and GRND_NONBLOCK,
|
||||
// neither of which have any effect on our current PRNG.
|
||||
// See <https://github.com/rust-lang/rust/pull/79196> for a discussion of argument sizes.
|
||||
let _flags = this.read_scalar(flags)?.to_i32()?;
|
||||
let _flags = ecx.read_scalar(flags)?.to_i32()?;
|
||||
|
||||
this.gen_random(ptr, len)?;
|
||||
this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
|
||||
ecx.gen_random(ptr, len)?;
|
||||
ecx.write_scalar(Scalar::from_target_usize(len, ecx), dest)?;
|
||||
}
|
||||
// `futex` is used by some synchronization primitives.
|
||||
num if num == sys_futex => {
|
||||
futex(this, args, dest)?;
|
||||
futex(ecx, args, dest)?;
|
||||
}
|
||||
num if num == sys_eventfd2 => {
|
||||
let [_, initval, flags] = check_min_arg_count("syscall(SYS_evetfd2, ...)", args)?;
|
||||
|
||||
let result = this.eventfd(initval, flags)?;
|
||||
this.write_int(result.to_i32()?, dest)?;
|
||||
let result = ecx.eventfd(initval, flags)?;
|
||||
ecx.write_int(result.to_i32()?, dest)?;
|
||||
}
|
||||
num => {
|
||||
throw_unsup_format!("syscall: unsupported syscall number {num}");
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
// Performs an AES round (given by `f`) on each 128-bit word of
|
||||
// `state` with the corresponding 128-bit key of `key`.
|
||||
fn aes_round<'tcx>(
|
||||
this: &mut crate::MiriInterpCx<'tcx>,
|
||||
ecx: &mut crate::MiriInterpCx<'tcx>,
|
||||
state: &OpTy<'tcx>,
|
||||
key: &OpTy<'tcx>,
|
||||
dest: &MPlaceTy<'tcx>,
|
||||
|
|
@ -145,21 +145,20 @@ fn aes_round<'tcx>(
|
|||
assert_eq!(dest.layout.size.bytes() % 16, 0);
|
||||
let len = dest.layout.size.bytes() / 16;
|
||||
|
||||
let u128_array_layout =
|
||||
this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u128, len))?;
|
||||
let u128_array_layout = ecx.layout_of(Ty::new_array(ecx.tcx.tcx, ecx.tcx.types.u128, len))?;
|
||||
|
||||
let state = state.transmute(u128_array_layout, this)?;
|
||||
let key = key.transmute(u128_array_layout, this)?;
|
||||
let dest = dest.transmute(u128_array_layout, this)?;
|
||||
let state = state.transmute(u128_array_layout, ecx)?;
|
||||
let key = key.transmute(u128_array_layout, ecx)?;
|
||||
let dest = dest.transmute(u128_array_layout, ecx)?;
|
||||
|
||||
for i in 0..len {
|
||||
let state = this.read_scalar(&this.project_index(&state, i)?)?.to_u128()?;
|
||||
let key = this.read_scalar(&this.project_index(&key, i)?)?.to_u128()?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
let state = ecx.read_scalar(&ecx.project_index(&state, i)?)?.to_u128()?;
|
||||
let key = ecx.read_scalar(&ecx.project_index(&key, i)?)?.to_u128()?;
|
||||
let dest = ecx.project_index(&dest, i)?;
|
||||
|
||||
let res = f(state, key);
|
||||
|
||||
this.write_scalar(Scalar::from_u128(res), &dest)?;
|
||||
ecx.write_scalar(Scalar::from_u128(res), &dest)?;
|
||||
}
|
||||
|
||||
interp_ok(())
|
||||
|
|
|
|||
|
|
@ -75,21 +75,21 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
/// If `inverse` is set, then the inverse transformation with respect to the reduction polynomial
|
||||
/// x^8 + x^4 + x^3 + x + 1 is performed instead.
|
||||
fn affine_transform<'tcx>(
|
||||
this: &mut MiriInterpCx<'tcx>,
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
left: &OpTy<'tcx>,
|
||||
right: &OpTy<'tcx>,
|
||||
imm8: &OpTy<'tcx>,
|
||||
dest: &MPlaceTy<'tcx>,
|
||||
inverse: bool,
|
||||
) -> InterpResult<'tcx, ()> {
|
||||
let (left, left_len) = this.project_to_simd(left)?;
|
||||
let (right, right_len) = this.project_to_simd(right)?;
|
||||
let (dest, dest_len) = this.project_to_simd(dest)?;
|
||||
let (left, left_len) = ecx.project_to_simd(left)?;
|
||||
let (right, right_len) = ecx.project_to_simd(right)?;
|
||||
let (dest, dest_len) = ecx.project_to_simd(dest)?;
|
||||
|
||||
assert_eq!(dest_len, right_len);
|
||||
assert_eq!(dest_len, left_len);
|
||||
|
||||
let imm8 = this.read_scalar(imm8)?.to_u8()?;
|
||||
let imm8 = ecx.read_scalar(imm8)?.to_u8()?;
|
||||
|
||||
// Each 8x8 bit matrix gets multiplied with eight bit vectors.
|
||||
// Therefore, the iteration is done in chunks of eight.
|
||||
|
|
@ -98,13 +98,13 @@ fn affine_transform<'tcx>(
|
|||
let mut matrix = [0u8; 8];
|
||||
for j in 0..8 {
|
||||
matrix[usize::try_from(j).unwrap()] =
|
||||
this.read_scalar(&this.project_index(&right, i.wrapping_add(j))?)?.to_u8()?;
|
||||
ecx.read_scalar(&ecx.project_index(&right, i.wrapping_add(j))?)?.to_u8()?;
|
||||
}
|
||||
|
||||
// Multiply the matrix with the vector and perform the addition.
|
||||
for j in 0..8 {
|
||||
let index = i.wrapping_add(j);
|
||||
let left = this.read_scalar(&this.project_index(&left, index)?)?.to_u8()?;
|
||||
let left = ecx.read_scalar(&ecx.project_index(&left, index)?)?.to_u8()?;
|
||||
let left = if inverse { TABLE[usize::from(left)] } else { left };
|
||||
|
||||
let mut res = 0;
|
||||
|
|
@ -124,8 +124,8 @@ fn affine_transform<'tcx>(
|
|||
// Perform the addition.
|
||||
res ^= imm8;
|
||||
|
||||
let dest = this.project_index(&dest, index)?;
|
||||
this.write_scalar(Scalar::from_u8(res), &dest)?;
|
||||
let dest = ecx.project_index(&dest, index)?;
|
||||
ecx.write_scalar(Scalar::from_u8(res), &dest)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -23,27 +23,27 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
// Prefix should have already been checked.
|
||||
let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sha").unwrap();
|
||||
|
||||
fn read<'c>(this: &mut MiriInterpCx<'c>, reg: &OpTy<'c>) -> InterpResult<'c, [u32; 4]> {
|
||||
fn read<'c>(ecx: &mut MiriInterpCx<'c>, reg: &OpTy<'c>) -> InterpResult<'c, [u32; 4]> {
|
||||
let mut res = [0; 4];
|
||||
// We reverse the order because x86 is little endian but the copied implementation uses
|
||||
// big endian.
|
||||
for (i, dst) in res.iter_mut().rev().enumerate() {
|
||||
let projected = &this.project_index(reg, i.try_into().unwrap())?;
|
||||
*dst = this.read_scalar(projected)?.to_u32()?
|
||||
let projected = &ecx.project_index(reg, i.try_into().unwrap())?;
|
||||
*dst = ecx.read_scalar(projected)?.to_u32()?
|
||||
}
|
||||
interp_ok(res)
|
||||
}
|
||||
|
||||
fn write<'c>(
|
||||
this: &mut MiriInterpCx<'c>,
|
||||
ecx: &mut MiriInterpCx<'c>,
|
||||
dest: &MPlaceTy<'c>,
|
||||
val: [u32; 4],
|
||||
) -> InterpResult<'c, ()> {
|
||||
// We reverse the order because x86 is little endian but the copied implementation uses
|
||||
// big endian.
|
||||
for (i, part) in val.into_iter().rev().enumerate() {
|
||||
let projected = &this.project_index(dest, i.try_into().unwrap())?;
|
||||
this.write_scalar(Scalar::from_u32(part), projected)?;
|
||||
let projected = &ecx.project_index(dest, i.try_into().unwrap())?;
|
||||
ecx.write_scalar(Scalar::from_u32(part), projected)?;
|
||||
}
|
||||
interp_ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ const USE_SIGNED: u8 = 2;
|
|||
/// For more information, see the Intel Software Developer's Manual, Vol. 2b, Chapter 4.1.
|
||||
#[expect(clippy::arithmetic_side_effects)]
|
||||
fn compare_strings<'tcx>(
|
||||
this: &mut MiriInterpCx<'tcx>,
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
str1: &OpTy<'tcx>,
|
||||
str2: &OpTy<'tcx>,
|
||||
len: Option<(u64, u64)>,
|
||||
|
|
@ -80,8 +80,8 @@ fn compare_strings<'tcx>(
|
|||
let (len1, len2) = if let Some(t) = len {
|
||||
t
|
||||
} else {
|
||||
let len1 = implicit_len(this, str1, imm)?.unwrap_or(default_len);
|
||||
let len2 = implicit_len(this, str2, imm)?.unwrap_or(default_len);
|
||||
let len1 = implicit_len(ecx, str1, imm)?.unwrap_or(default_len);
|
||||
let len2 = implicit_len(ecx, str2, imm)?.unwrap_or(default_len);
|
||||
(len1, len2)
|
||||
};
|
||||
|
||||
|
|
@ -90,12 +90,12 @@ fn compare_strings<'tcx>(
|
|||
0 => {
|
||||
// Equal any: Checks which characters of `str2` are inside `str1`.
|
||||
for i in 0..len2 {
|
||||
let ch2 = this.read_immediate(&this.project_index(str2, i)?)?;
|
||||
let ch2 = ecx.read_immediate(&ecx.project_index(str2, i)?)?;
|
||||
|
||||
for j in 0..len1 {
|
||||
let ch1 = this.read_immediate(&this.project_index(str1, j)?)?;
|
||||
let ch1 = ecx.read_immediate(&ecx.project_index(str1, j)?)?;
|
||||
|
||||
let eq = this.binary_op(mir::BinOp::Eq, &ch1, &ch2)?;
|
||||
let eq = ecx.binary_op(mir::BinOp::Eq, &ch1, &ch2)?;
|
||||
if eq.to_scalar().to_bool()? {
|
||||
result |= 1 << i;
|
||||
break;
|
||||
|
|
@ -119,9 +119,9 @@ fn compare_strings<'tcx>(
|
|||
|
||||
for i in 0..len2 {
|
||||
for j in (0..len1).step_by(2) {
|
||||
let ch2 = get_ch(this.read_scalar(&this.project_index(str2, i)?)?)?;
|
||||
let ch1_1 = get_ch(this.read_scalar(&this.project_index(str1, j)?)?)?;
|
||||
let ch1_2 = get_ch(this.read_scalar(&this.project_index(str1, j + 1)?)?)?;
|
||||
let ch2 = get_ch(ecx.read_scalar(&ecx.project_index(str2, i)?)?)?;
|
||||
let ch1_1 = get_ch(ecx.read_scalar(&ecx.project_index(str1, j)?)?)?;
|
||||
let ch1_2 = get_ch(ecx.read_scalar(&ecx.project_index(str1, j + 1)?)?)?;
|
||||
|
||||
if ch1_1 <= ch2 && ch2 <= ch1_2 {
|
||||
result |= 1 << i;
|
||||
|
|
@ -135,9 +135,9 @@ fn compare_strings<'tcx>(
|
|||
result ^= (1 << len1.max(len2)) - 1;
|
||||
|
||||
for i in 0..len1.min(len2) {
|
||||
let ch1 = this.read_immediate(&this.project_index(str1, i)?)?;
|
||||
let ch2 = this.read_immediate(&this.project_index(str2, i)?)?;
|
||||
let eq = this.binary_op(mir::BinOp::Eq, &ch1, &ch2)?;
|
||||
let ch1 = ecx.read_immediate(&ecx.project_index(str1, i)?)?;
|
||||
let ch2 = ecx.read_immediate(&ecx.project_index(str2, i)?)?;
|
||||
let eq = ecx.binary_op(mir::BinOp::Eq, &ch1, &ch2)?;
|
||||
result |= i32::from(eq.to_scalar().to_bool()?) << i;
|
||||
}
|
||||
}
|
||||
|
|
@ -159,9 +159,9 @@ fn compare_strings<'tcx>(
|
|||
if k >= default_len {
|
||||
break;
|
||||
} else {
|
||||
let ch1 = this.read_immediate(&this.project_index(str1, j)?)?;
|
||||
let ch2 = this.read_immediate(&this.project_index(str2, k)?)?;
|
||||
let ne = this.binary_op(mir::BinOp::Ne, &ch1, &ch2)?;
|
||||
let ch1 = ecx.read_immediate(&ecx.project_index(str1, j)?)?;
|
||||
let ch2 = ecx.read_immediate(&ecx.project_index(str2, k)?)?;
|
||||
let ne = ecx.binary_op(mir::BinOp::Ne, &ch1, &ch2)?;
|
||||
|
||||
if ne.to_scalar().to_bool()? {
|
||||
result &= !(1 << i);
|
||||
|
|
@ -198,16 +198,16 @@ fn compare_strings<'tcx>(
|
|||
/// corresponding to the x86 128-bit integer SIMD type.
|
||||
fn deconstruct_args<'tcx>(
|
||||
unprefixed_name: &str,
|
||||
this: &mut MiriInterpCx<'tcx>,
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
link_name: Symbol,
|
||||
abi: ExternAbi,
|
||||
args: &[OpTy<'tcx>],
|
||||
) -> InterpResult<'tcx, (OpTy<'tcx>, OpTy<'tcx>, Option<(u64, u64)>, u8)> {
|
||||
let array_layout_fn = |this: &mut MiriInterpCx<'tcx>, imm: u8| {
|
||||
let array_layout_fn = |ecx: &mut MiriInterpCx<'tcx>, imm: u8| {
|
||||
if imm & USE_WORDS != 0 {
|
||||
this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u16, 8))
|
||||
ecx.layout_of(Ty::new_array(ecx.tcx.tcx, ecx.tcx.types.u16, 8))
|
||||
} else {
|
||||
this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u8, 16))
|
||||
ecx.layout_of(Ty::new_array(ecx.tcx.tcx, ecx.tcx.types.u8, 16))
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -223,26 +223,26 @@ fn deconstruct_args<'tcx>(
|
|||
|
||||
if is_explicit {
|
||||
let [str1, len1, str2, len2, imm] =
|
||||
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
|
||||
let imm = this.read_scalar(imm)?.to_u8()?;
|
||||
ecx.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
|
||||
let imm = ecx.read_scalar(imm)?.to_u8()?;
|
||||
|
||||
let default_len = default_len::<u32>(imm);
|
||||
let len1 = u64::from(this.read_scalar(len1)?.to_u32()?.min(default_len));
|
||||
let len2 = u64::from(this.read_scalar(len2)?.to_u32()?.min(default_len));
|
||||
let len1 = u64::from(ecx.read_scalar(len1)?.to_u32()?.min(default_len));
|
||||
let len2 = u64::from(ecx.read_scalar(len2)?.to_u32()?.min(default_len));
|
||||
|
||||
let array_layout = array_layout_fn(this, imm)?;
|
||||
let str1 = str1.transmute(array_layout, this)?;
|
||||
let str2 = str2.transmute(array_layout, this)?;
|
||||
let array_layout = array_layout_fn(ecx, imm)?;
|
||||
let str1 = str1.transmute(array_layout, ecx)?;
|
||||
let str2 = str2.transmute(array_layout, ecx)?;
|
||||
|
||||
interp_ok((str1, str2, Some((len1, len2)), imm))
|
||||
} else {
|
||||
let [str1, str2, imm] =
|
||||
this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
|
||||
let imm = this.read_scalar(imm)?.to_u8()?;
|
||||
ecx.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?;
|
||||
let imm = ecx.read_scalar(imm)?.to_u8()?;
|
||||
|
||||
let array_layout = array_layout_fn(this, imm)?;
|
||||
let str1 = str1.transmute(array_layout, this)?;
|
||||
let str2 = str2.transmute(array_layout, this)?;
|
||||
let array_layout = array_layout_fn(ecx, imm)?;
|
||||
let str1 = str1.transmute(array_layout, ecx)?;
|
||||
let str2 = str2.transmute(array_layout, ecx)?;
|
||||
|
||||
interp_ok((str1, str2, None, imm))
|
||||
}
|
||||
|
|
@ -251,16 +251,16 @@ fn deconstruct_args<'tcx>(
|
|||
/// Calculate the c-style string length for a given string `str`.
|
||||
/// The string is either a length 16 array of bytes a length 8 array of two-byte words.
|
||||
fn implicit_len<'tcx>(
|
||||
this: &mut MiriInterpCx<'tcx>,
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
str: &OpTy<'tcx>,
|
||||
imm: u8,
|
||||
) -> InterpResult<'tcx, Option<u64>> {
|
||||
let mut result = None;
|
||||
let zero = ImmTy::from_int(0, str.layout.field(this, 0));
|
||||
let zero = ImmTy::from_int(0, str.layout.field(ecx, 0));
|
||||
|
||||
for i in 0..default_len::<u64>(imm) {
|
||||
let ch = this.read_immediate(&this.project_index(str, i)?)?;
|
||||
let is_zero = this.binary_op(mir::BinOp::Eq, &ch, &zero)?;
|
||||
let ch = ecx.read_immediate(&ecx.project_index(str, i)?)?;
|
||||
let is_zero = ecx.binary_op(mir::BinOp::Eq, &ch, &zero)?;
|
||||
if is_zero.to_scalar().to_bool()? {
|
||||
result = Some(i);
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue