Auto merge of #2455 - RalfJung:scalar-always-init, r=RalfJung

adjust for earlier init checking in the core engine

Miri side of https://github.com/rust-lang/rust/pull/100043
This commit is contained in:
bors 2022-08-27 13:17:31 +00:00
commit bb8212484f
39 changed files with 178 additions and 247 deletions

View File

@ -1 +1 @@
e1b28cd2f16bd5b832183d7968cae3bb9213e78d
4065b89b1e7287047d7d6c65e7abd7b8ee70bcf0

View File

@ -447,7 +447,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
offset: u64,
layout: TyAndLayout<'tcx>,
atomic: AtomicReadOrd,
) -> InterpResult<'tcx, ScalarMaybeUninit<Provenance>> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_ref();
let value_place = this.deref_operand_and_offset(op, offset, layout)?;
this.read_scalar_atomic(&value_place, atomic)
@ -458,7 +458,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
&mut self,
op: &OpTy<'tcx, Provenance>,
offset: u64,
value: impl Into<ScalarMaybeUninit<Provenance>>,
value: impl Into<Scalar<Provenance>>,
layout: TyAndLayout<'tcx>,
atomic: AtomicWriteOrd,
) -> InterpResult<'tcx> {
@ -472,7 +472,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
&self,
place: &MPlaceTy<'tcx, Provenance>,
atomic: AtomicReadOrd,
) -> InterpResult<'tcx, ScalarMaybeUninit<Provenance>> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_ref();
this.atomic_access_check(place)?;
// This will read from the last store in the modification order of this location. In case
@ -490,7 +490,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
/// Perform an atomic write operation at the memory location.
fn write_scalar_atomic(
&mut self,
val: ScalarMaybeUninit<Provenance>,
val: Scalar<Provenance>,
dest: &MPlaceTy<'tcx, Provenance>,
atomic: AtomicWriteOrd,
) -> InterpResult<'tcx> {
@ -530,12 +530,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
this.validate_atomic_rmw(place, atomic)?;
this.buffered_atomic_rmw(
val.to_scalar_or_uninit(),
place,
atomic,
old.to_scalar_or_uninit(),
)?;
this.buffered_atomic_rmw(val.to_scalar(), place, atomic, old.to_scalar())?;
Ok(old)
}
@ -544,9 +539,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
fn atomic_exchange_scalar(
&mut self,
place: &MPlaceTy<'tcx, Provenance>,
new: ScalarMaybeUninit<Provenance>,
new: Scalar<Provenance>,
atomic: AtomicRwOrd,
) -> InterpResult<'tcx, ScalarMaybeUninit<Provenance>> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
this.atomic_access_check(place)?;
@ -574,7 +569,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
this.validate_overlapping_atomic(place)?;
let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?;
let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar()?.to_bool()?;
let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?;
let new_val = if min {
if lt { &old } else { &rhs }
@ -586,12 +581,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
this.validate_atomic_rmw(place, atomic)?;
this.buffered_atomic_rmw(
new_val.to_scalar_or_uninit(),
place,
atomic,
old.to_scalar_or_uninit(),
)?;
this.buffered_atomic_rmw(new_val.to_scalar(), place, atomic, old.to_scalar())?;
// Return the old value.
Ok(old)
@ -607,7 +597,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
&mut self,
place: &MPlaceTy<'tcx, Provenance>,
expect_old: &ImmTy<'tcx, Provenance>,
new: ScalarMaybeUninit<Provenance>,
new: Scalar<Provenance>,
success: AtomicRwOrd,
fail: AtomicReadOrd,
can_fail_spuriously: bool,
@ -627,16 +617,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
// If the operation would succeed, but is "weak", fail some portion
// of the time, based on `success_rate`.
let success_rate = 1.0 - this.machine.cmpxchg_weak_failure_rate;
let cmpxchg_success = eq.to_scalar()?.to_bool()?
let cmpxchg_success = eq.to_scalar().to_bool()?
&& if can_fail_spuriously {
this.machine.rng.get_mut().gen_bool(success_rate)
} else {
true
};
let res = Immediate::ScalarPair(
old.to_scalar_or_uninit(),
Scalar::from_bool(cmpxchg_success).into(),
);
let res = Immediate::ScalarPair(old.to_scalar(), Scalar::from_bool(cmpxchg_success));
// Update ptr depending on comparison.
// if successful, perform a full rw-atomic validation
@ -644,14 +631,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
if cmpxchg_success {
this.allow_data_races_mut(|this| this.write_scalar(new, &place.into()))?;
this.validate_atomic_rmw(place, success)?;
this.buffered_atomic_rmw(new, place, success, old.to_scalar_or_uninit())?;
this.buffered_atomic_rmw(new, place, success, old.to_scalar())?;
} else {
this.validate_atomic_load(place, fail)?;
// A failed compare exchange is equivalent to a load, reading from the latest store
// in the modification order.
// Since `old` is only a value and not the store element, we need to separately
// find it in our store buffer and perform load_impl on it.
this.perform_read_on_buffered_latest(place, fail, old.to_scalar_or_uninit())?;
this.perform_read_on_buffered_latest(place, fail, old.to_scalar())?;
}
// Return the old value.

View File

@ -77,9 +77,7 @@ use std::{
collections::VecDeque,
};
use rustc_const_eval::interpret::{
alloc_range, AllocRange, InterpResult, MPlaceTy, ScalarMaybeUninit,
};
use rustc_const_eval::interpret::{alloc_range, AllocRange, InterpResult, MPlaceTy, Scalar};
use rustc_data_structures::fx::FxHashMap;
use crate::*;
@ -130,10 +128,10 @@ struct StoreElement {
/// The timestamp of the storing thread when it performed the store
timestamp: VTimestamp,
/// The value of this store
// FIXME: this means the store is either fully initialized or fully uninitialized;
// FIXME: this means the store must be fully initialized;
// we will have to change this if we want to support atomics on
// partially initialized data.
val: ScalarMaybeUninit<Provenance>,
// (partially) uninitialized data.
val: Scalar<Provenance>,
/// Timestamp of first loads from this store element by each thread
/// Behind a RefCell to keep load op take &self
@ -180,7 +178,7 @@ impl StoreBufferAlloc {
fn get_or_create_store_buffer<'tcx>(
&self,
range: AllocRange,
init: ScalarMaybeUninit<Provenance>,
init: Scalar<Provenance>,
) -> InterpResult<'tcx, Ref<'_, StoreBuffer>> {
let access_type = self.store_buffers.borrow().access_type(range);
let pos = match access_type {
@ -205,7 +203,7 @@ impl StoreBufferAlloc {
fn get_or_create_store_buffer_mut<'tcx>(
&mut self,
range: AllocRange,
init: ScalarMaybeUninit<Provenance>,
init: Scalar<Provenance>,
) -> InterpResult<'tcx, &mut StoreBuffer> {
let buffers = self.store_buffers.get_mut();
let access_type = buffers.access_type(range);
@ -226,7 +224,7 @@ impl StoreBufferAlloc {
}
impl<'mir, 'tcx: 'mir> StoreBuffer {
fn new(init: ScalarMaybeUninit<Provenance>) -> Self {
fn new(init: Scalar<Provenance>) -> Self {
let mut buffer = VecDeque::new();
buffer.reserve(STORE_BUFFER_LIMIT);
let mut ret = Self { buffer };
@ -259,7 +257,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer {
is_seqcst: bool,
rng: &mut (impl rand::Rng + ?Sized),
validate: impl FnOnce() -> InterpResult<'tcx>,
) -> InterpResult<'tcx, (ScalarMaybeUninit<Provenance>, LoadRecency)> {
) -> InterpResult<'tcx, (Scalar<Provenance>, LoadRecency)> {
// Having a live borrow to store_buffer while calling validate_atomic_load is fine
// because the race detector doesn't touch store_buffer
@ -284,7 +282,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer {
fn buffered_write(
&mut self,
val: ScalarMaybeUninit<Provenance>,
val: Scalar<Provenance>,
global: &DataRaceState,
thread_mgr: &ThreadManager<'_, '_>,
is_seqcst: bool,
@ -375,7 +373,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer {
/// ATOMIC STORE IMPL in the paper (except we don't need the location's vector clock)
fn store_impl(
&mut self,
val: ScalarMaybeUninit<Provenance>,
val: Scalar<Provenance>,
index: VectorIdx,
thread_clock: &VClock,
is_seqcst: bool,
@ -417,11 +415,7 @@ impl StoreElement {
/// buffer regardless of subsequent loads by the same thread; if the earliest load of another
/// thread doesn't happen before the current one, then no subsequent load by the other thread
/// can happen before the current one.
fn load_impl(
&self,
index: VectorIdx,
clocks: &ThreadClockSet,
) -> ScalarMaybeUninit<Provenance> {
fn load_impl(&self, index: VectorIdx, clocks: &ThreadClockSet) -> Scalar<Provenance> {
let _ = self.loads.borrow_mut().try_insert(index, clocks.clock[index]);
self.val
}
@ -464,10 +458,10 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
fn buffered_atomic_rmw(
&mut self,
new_val: ScalarMaybeUninit<Provenance>,
new_val: Scalar<Provenance>,
place: &MPlaceTy<'tcx, Provenance>,
atomic: AtomicRwOrd,
init: ScalarMaybeUninit<Provenance>,
init: Scalar<Provenance>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?;
@ -492,9 +486,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
&self,
place: &MPlaceTy<'tcx, Provenance>,
atomic: AtomicReadOrd,
latest_in_mo: ScalarMaybeUninit<Provenance>,
latest_in_mo: Scalar<Provenance>,
validate: impl FnOnce() -> InterpResult<'tcx>,
) -> InterpResult<'tcx, ScalarMaybeUninit<Provenance>> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_ref();
if let Some(global) = &this.machine.data_race {
let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?;
@ -529,10 +523,10 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
fn buffered_atomic_write(
&mut self,
val: ScalarMaybeUninit<Provenance>,
val: Scalar<Provenance>,
dest: &MPlaceTy<'tcx, Provenance>,
atomic: AtomicWriteOrd,
init: ScalarMaybeUninit<Provenance>,
init: Scalar<Provenance>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?;
@ -576,7 +570,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
&self,
place: &MPlaceTy<'tcx, Provenance>,
atomic: AtomicReadOrd,
init: ScalarMaybeUninit<Provenance>,
init: Scalar<Provenance>,
) -> InterpResult<'tcx> {
let this = self.eval_context_ref();

View File

@ -116,8 +116,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let instance = this.resolve_path(path);
let cid = GlobalId { instance, promoted: None };
let const_val = this.eval_to_allocation(cid)?;
let const_val = this.read_scalar(&const_val.into())?;
const_val.check_init()
this.read_scalar(&const_val.into())
}
/// Helper function to get a `libc` constant as a `Scalar`.
@ -567,7 +566,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
let errno_place = this.last_error_place()?;
this.read_scalar(&errno_place.into())?.check_init()
this.read_scalar(&errno_place.into())
}
/// This function tries to produce the most similar OS error from the `std::io::ErrorKind`
@ -680,22 +679,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
op: &OpTy<'tcx, Provenance>,
offset: u64,
layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, ScalarMaybeUninit<Provenance>> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_ref();
let value_place = this.deref_operand_and_offset(op, offset, layout)?;
this.read_scalar(&value_place.into())
}
fn write_immediate_at_offset(
&mut self,
op: &OpTy<'tcx, Provenance>,
offset: u64,
value: &ImmTy<'tcx, Provenance>,
) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let value_place = this.deref_operand_and_offset(op, offset, value.layout)?;
this.write_immediate(**value, &value_place.into())
}
fn write_scalar_at_offset(
&mut self,
op: &OpTy<'tcx, Provenance>,
offset: u64,
value: impl Into<ScalarMaybeUninit<Provenance>>,
value: impl Into<Scalar<Provenance>>,
layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let value_place = this.deref_operand_and_offset(op, offset, layout)?;
this.write_scalar(value, &value_place.into())
self.write_immediate_at_offset(op, offset, &ImmTy::from_scalar(value.into(), layout))
}
/// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None`

View File

@ -149,7 +149,7 @@ static_assert_size!(Pointer<Provenance>, 24);
// #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
//static_assert_size!(Pointer<Option<Provenance>>, 24);
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(ScalarMaybeUninit<Provenance>, 32);
static_assert_size!(Scalar<Provenance>, 32);
impl interpret::Provenance for Provenance {
/// We use absolute addresses in the `offset` of a `Pointer<Provenance>`.
@ -581,7 +581,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
}
#[inline(always)]
fn force_int_for_alignment_check(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool {
fn use_addr_for_alignment_check(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool {
ecx.machine.check_alignment == AlignmentCheck::Int
}
@ -590,11 +590,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
ecx.machine.validate
}
#[inline(always)]
fn enforce_number_init(_ecx: &MiriEvalContext<'mir, 'tcx>) -> bool {
true
}
#[inline(always)]
fn enforce_abi(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool {
ecx.machine.enforce_abi

View File

@ -32,16 +32,14 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
// Just compare the bits. ScalarPairs are compared lexicographically.
// We thus always compare pairs and simply fill scalars up with 0.
let left = match **left {
Immediate::Scalar(l) => (l.check_init()?.to_bits(size)?, 0),
Immediate::ScalarPair(l1, l2) =>
(l1.check_init()?.to_bits(size)?, l2.check_init()?.to_bits(size)?),
Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
Immediate::Scalar(l) => (l.to_bits(size)?, 0),
Immediate::ScalarPair(l1, l2) => (l1.to_bits(size)?, l2.to_bits(size)?),
Immediate::Uninit => panic!("we should never see uninit data here"),
};
let right = match **right {
Immediate::Scalar(r) => (r.check_init()?.to_bits(size)?, 0),
Immediate::ScalarPair(r1, r2) =>
(r1.check_init()?.to_bits(size)?, r2.check_init()?.to_bits(size)?),
Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
Immediate::Scalar(r) => (r.to_bits(size)?, 0),
Immediate::ScalarPair(r1, r2) => (r1.to_bits(size)?, r2.to_bits(size)?),
Immediate::Uninit => panic!("we should never see uninit data here"),
};
let res = match bin_op {
Eq => left == right,
@ -57,8 +55,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
Offset => {
assert!(left.layout.ty.is_unsafe_ptr());
let ptr = left.to_scalar()?.to_pointer(self)?;
let offset = right.to_scalar()?.to_machine_isize(self)?;
let ptr = left.to_scalar().to_pointer(self)?;
let offset = right.to_scalar().to_machine_isize(self)?;
let pointee_ty =
left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty;
@ -71,11 +69,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> {
Add | Sub | BitOr | BitAnd | BitXor => {
assert!(left.layout.ty.is_unsafe_ptr());
assert!(right.layout.ty.is_unsafe_ptr());
let ptr = left.to_scalar()?.to_pointer(self)?;
let ptr = left.to_scalar().to_pointer(self)?;
// We do the actual operation with usize-typed scalars.
let left = ImmTy::from_uint(ptr.addr().bytes(), self.machine.layouts.usize);
let right = ImmTy::from_uint(
right.to_scalar()?.to_machine_usize(self)?,
right.to_scalar().to_machine_usize(self)?,
self.machine.layouts.usize,
);
let (result, overflowing, _ty) =

View File

@ -13,7 +13,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
/// Extract the scalar value from the result of reading a scalar from the machine,
/// and convert it to a `CArg`.
fn scalar_to_carg(
k: ScalarMaybeUninit<Provenance>,
k: Scalar<Provenance>,
arg_type: Ty<'tcx>,
cx: &impl HasDataLayout,
) -> InterpResult<'tcx, CArg> {

View File

@ -226,8 +226,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
};
let float_finite = |x: &ImmTy<'tcx, _>| -> InterpResult<'tcx, bool> {
Ok(match x.layout.ty.kind() {
ty::Float(FloatTy::F32) => x.to_scalar()?.to_f32()?.is_finite(),
ty::Float(FloatTy::F64) => x.to_scalar()?.to_f64()?.is_finite(),
ty::Float(FloatTy::F32) => x.to_scalar().to_f32()?.is_finite(),
ty::Float(FloatTy::F64) => x.to_scalar().to_f64()?.is_finite(),
_ => bug!(
"`{intrinsic_name}` called with non-float input type {ty:?}",
ty = x.layout.ty,
@ -345,9 +345,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let res = match val.layout.ty.kind() {
ty::Float(FloatTy::F32) =>
this.float_to_int_unchecked(val.to_scalar()?.to_f32()?, dest.layout.ty)?,
this.float_to_int_unchecked(val.to_scalar().to_f32()?, dest.layout.ty)?,
ty::Float(FloatTy::F64) =>
this.float_to_int_unchecked(val.to_scalar()?.to_f64()?, dest.layout.ty)?,
this.float_to_int_unchecked(val.to_scalar().to_f64()?, dest.layout.ty)?,
_ =>
span_bug!(
this.cur_span(),

View File

@ -60,13 +60,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?;
let dest = this.mplace_index(&dest, i)?;
let val = match which {
Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar()?,
Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar(),
Op::Abs => {
// Works for f32 and f64.
let ty::Float(float_ty) = op.layout.ty.kind() else {
span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name)
};
let op = op.to_scalar()?;
let op = op.to_scalar();
match float_ty {
FloatTy::F32 => Scalar::from_f32(op.to_f32()?.abs()),
FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()),
@ -79,7 +79,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// FIXME using host floats
match float_ty {
FloatTy::F32 => {
let f = f32::from_bits(op.to_scalar()?.to_u32()?);
let f = f32::from_bits(op.to_scalar().to_u32()?);
let res = match host_op {
HostFloatOp::Ceil => f.ceil(),
HostFloatOp::Floor => f.floor(),
@ -90,7 +90,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
Scalar::from_u32(res.to_bits())
}
FloatTy::F64 => {
let f = f64::from_bits(op.to_scalar()?.to_u64()?);
let f = f64::from_bits(op.to_scalar().to_u64()?);
let res = match host_op {
HostFloatOp::Ceil => f.ceil(),
HostFloatOp::Floor => f.floor(),
@ -182,7 +182,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// Shifts have extra UB as SIMD operations that the MIR binop does not have.
// See <https://github.com/rust-lang/rust/issues/91237>.
if overflowed {
let r_val = right.to_scalar()?.to_bits(right.layout.size)?;
let r_val = right.to_scalar().to_bits(right.layout.size)?;
throw_ub_format!("overflowing shift by {r_val} in `simd_{intrinsic_name}` in SIMD lane {i}");
}
}
@ -201,8 +201,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.saturating_arith(mir_op, &left, &right)?
}
Op::WrappingOffset => {
let ptr = left.to_scalar()?.to_pointer(this)?;
let offset_count = right.to_scalar()?.to_machine_isize(this)?;
let ptr = left.to_scalar().to_pointer(this)?;
let offset_count = right.to_scalar().to_machine_isize(this)?;
let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty;
let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap();
@ -232,9 +232,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
assert_eq!(dest_len, c_len);
for i in 0..dest_len {
let a = this.read_immediate(&this.mplace_index(&a, i)?.into())?.to_scalar()?;
let b = this.read_immediate(&this.mplace_index(&b, i)?.into())?.to_scalar()?;
let c = this.read_immediate(&this.mplace_index(&c, i)?.into())?.to_scalar()?;
let a = this.read_scalar(&this.mplace_index(&a, i)?.into())?;
let b = this.read_scalar(&this.mplace_index(&b, i)?.into())?;
let c = this.read_scalar(&this.mplace_index(&c, i)?.into())?;
let dest = this.mplace_index(&dest, i)?;
// Works for f32 and f64.
@ -315,7 +315,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
ImmTy::from_scalar(fmax_op(&res, &op)?, res.layout)
} else {
// Just boring integers, so NaNs to worry about
if this.binary_op(BinOp::Ge, &res, &op)?.to_scalar()?.to_bool()? {
if this.binary_op(BinOp::Ge, &res, &op)?.to_scalar().to_bool()? {
res
} else {
op
@ -327,7 +327,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
ImmTy::from_scalar(fmin_op(&res, &op)?, res.layout)
} else {
// Just boring integers, so NaNs to worry about
if this.binary_op(BinOp::Le, &res, &op)?.to_scalar()?.to_bool()? {
if this.binary_op(BinOp::Le, &res, &op)?.to_scalar().to_bool()? {
res
} else {
op
@ -396,12 +396,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let dest_len = u32::try_from(dest_len).unwrap();
let bitmask_len = u32::try_from(bitmask_len).unwrap();
let mask: u64 = this
.read_scalar(mask)?
.check_init()?
.to_bits(mask.layout.size)?
.try_into()
.unwrap();
let mask: u64 =
this.read_scalar(mask)?.to_bits(mask.layout.size)?.try_into().unwrap();
for i in 0..dest_len {
let mask = mask
& 1u64
@ -450,9 +446,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.misc_cast(&op, dest.layout.ty)?,
// Float-to-int in unchecked mode
(ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if !safe_cast =>
this.float_to_int_unchecked(op.to_scalar()?.to_f32()?, dest.layout.ty)?.into(),
this.float_to_int_unchecked(op.to_scalar().to_f32()?, dest.layout.ty)?.into(),
(ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if !safe_cast =>
this.float_to_int_unchecked(op.to_scalar()?.to_f64()?, dest.layout.ty)?.into(),
this.float_to_int_unchecked(op.to_scalar().to_f64()?, dest.layout.ty)?.into(),
_ =>
throw_unsup_format!(
"Unsupported SIMD cast from element type {from_ty} to {to_ty}",
@ -481,7 +477,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
for i in 0..dest_len {
let src_index: u64 = this
.read_immediate(&this.operand_index(index, i)?)?
.to_scalar()?
.to_scalar()
.to_u32()?
.into();
let dest = this.mplace_index(&dest, i)?;
@ -581,7 +577,7 @@ fn bool_to_simd_element(b: bool, size: Size) -> Scalar<Provenance> {
}
fn simd_element_to_bool(elem: ImmTy<'_, Provenance>) -> InterpResult<'_, bool> {
let val = elem.to_scalar()?.to_int(elem.layout.size)?;
let val = elem.to_scalar().to_int(elem.layout.size)?;
Ok(match val {
0 => false,
-1 => true,
@ -606,8 +602,8 @@ fn fmax_op<'tcx>(
let ty::Float(float_ty) = left.layout.ty.kind() else {
bug!("fmax operand is not a float")
};
let left = left.to_scalar()?;
let right = right.to_scalar()?;
let left = left.to_scalar();
let right = right.to_scalar();
Ok(match float_ty {
FloatTy::F32 => Scalar::from_f32(left.to_f32()?.max(right.to_f32()?)),
FloatTy::F64 => Scalar::from_f64(left.to_f64()?.max(right.to_f64()?)),
@ -622,8 +618,8 @@ fn fmin_op<'tcx>(
let ty::Float(float_ty) = left.layout.ty.kind() else {
bug!("fmin operand is not a float")
};
let left = left.to_scalar()?;
let right = right.to_scalar()?;
let left = left.to_scalar();
let right = right.to_scalar();
Ok(match float_ty {
FloatTy::F32 => Scalar::from_f32(left.to_f32()?.min(right.to_f32()?)),
FloatTy::F64 => Scalar::from_f64(left.to_f64()?.min(right.to_f64()?)),

View File

@ -156,8 +156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
.unwrap(); // not a ZST, so we will get a result
for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() {
let offset = u64::try_from(offset).unwrap();
alloc
.write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar).into())?;
alloc.write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar))?;
}
Ok((true, string_length))
}

View File

@ -52,7 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// Get the raw pointer stored in arg[0] (the panic payload).
let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?;
let payload = this.read_scalar(payload)?.check_init()?;
let payload = this.read_scalar(payload)?;
let thread = this.active_thread_mut();
assert!(thread.panic_payload.is_none(), "the panic runtime should avoid double-panics");
thread.panic_payload = Some(payload);
@ -85,7 +85,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// Get all the arguments.
let [try_fn, data, catch_fn] = check_arg_count(args)?;
let try_fn = this.read_pointer(try_fn)?;
let data = this.read_scalar(data)?.check_init()?;
let data = this.read_scalar(data)?;
let catch_fn = this.read_pointer(catch_fn)?;
// Now we make a function call, and pass `data` as first and only argument.

View File

@ -283,24 +283,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
"pthread_key_delete" => {
let [key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?;
let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
this.machine.tls.delete_tls_key(key)?;
// Return success (0)
this.write_null(dest)?;
}
"pthread_getspecific" => {
let [key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?;
let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
let active_thread = this.get_active_thread();
let ptr = this.machine.tls.load_tls(key, active_thread, this)?;
this.write_scalar(ptr, dest)?;
}
"pthread_setspecific" => {
let [key, new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?;
let key = this.read_scalar(key)?.to_bits(key.layout.size)?;
let active_thread = this.get_active_thread();
let new_data = this.read_scalar(new_ptr)?;
this.machine.tls.store_tls(key, active_thread, new_data.check_init()?, &*this.tcx)?;
this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
// Return success (`0`).
this.write_null(dest)?;
@ -465,7 +465,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
"strerror_r" | "__xpg_strerror_r" => {
let [errnum, buf, buflen] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let errnum = this.read_scalar(errnum)?.check_init()?;
let errnum = this.read_scalar(errnum)?;
let buf = this.read_pointer(buf)?;
let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?;

View File

@ -26,10 +26,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
"pthread_set_name_np" => {
let [thread, name] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let res = this.pthread_setname_np(
this.read_scalar(thread)?.check_init()?,
this.read_scalar(name)?.check_init()?,
)?;
let res =
this.pthread_setname_np(this.read_scalar(thread)?, this.read_scalar(name)?)?;
this.write_scalar(res, dest)?;
}
@ -37,7 +35,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
"__error" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let errno_place = this.last_error_place()?;
this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?;
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
_ => return Ok(EmulateByNameResult::NotSupported),

View File

@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
"__errno_location" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let errno_place = this.last_error_place()?;
this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?;
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
// File related shims (but also see "syscall" below for statx)
@ -68,10 +68,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
"pthread_setname_np" => {
let [thread, name] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let res = this.pthread_setname_np(
this.read_scalar(thread)?.check_init()?,
this.read_scalar(name)?.check_init()?,
)?;
let res =
this.pthread_setname_np(this.read_scalar(thread)?, this.read_scalar(name)?)?;
this.write_scalar(res, dest)?;
}

View File

@ -33,7 +33,7 @@ pub fn futex<'tcx>(
let val = this.read_scalar(&args[2])?.to_i32()?;
let thread = this.get_active_thread();
let addr_scalar = addr.to_scalar()?;
let addr_scalar = addr.to_scalar();
let addr_usize = addr_scalar.to_machine_usize(this)?;
let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?;

View File

@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
"__error" => {
let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let errno_place = this.last_error_place()?;
this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?;
this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
}
// File related shims
@ -153,7 +153,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let dtor = this.read_pointer(dtor)?;
let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
let data = this.read_scalar(data)?.check_init()?;
let data = this.read_scalar(data)?;
let active_thread = this.get_active_thread();
this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?;
}
@ -176,7 +176,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
"pthread_setname_np" => {
let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let thread = this.pthread_self()?;
this.pthread_setname_np(thread, this.read_scalar(name)?.check_init()?)?;
this.pthread_setname_np(thread, this.read_scalar(name)?)?;
}
// Incomplete shims that we "stub out" just to get pre-main initialization code to work.
@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value.
let [addr, _, _, _, _, _] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let addr = this.read_scalar(addr)?.check_init()?;
let addr = this.read_scalar(addr)?;
this.write_scalar(addr, dest)?;
}

View File

@ -38,14 +38,14 @@ fn is_mutex_kind_normal<'mir, 'tcx: 'mir>(
fn mutexattr_get_kind<'mir, 'tcx: 'mir>(
ecx: &MiriEvalContext<'mir, 'tcx>,
attr_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, ScalarMaybeUninit<Provenance>> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32)
}
fn mutexattr_set_kind<'mir, 'tcx: 'mir>(
ecx: &mut MiriEvalContext<'mir, 'tcx>,
attr_op: &OpTy<'tcx, Provenance>,
kind: impl Into<ScalarMaybeUninit<Provenance>>,
kind: impl Into<Scalar<Provenance>>,
) -> InterpResult<'tcx, ()> {
ecx.write_scalar_at_offset(attr_op, 0, kind, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32))
}
@ -62,7 +62,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>(
fn mutex_get_kind<'mir, 'tcx: 'mir>(
ecx: &MiriEvalContext<'mir, 'tcx>,
mutex_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, ScalarMaybeUninit<Provenance>> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
ecx.read_scalar_at_offset_atomic(
mutex_op,
@ -75,7 +75,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>(
fn mutex_set_kind<'mir, 'tcx: 'mir>(
ecx: &mut MiriEvalContext<'mir, 'tcx>,
mutex_op: &OpTy<'tcx, Provenance>,
kind: impl Into<ScalarMaybeUninit<Provenance>>,
kind: impl Into<Scalar<Provenance>>,
) -> InterpResult<'tcx, ()> {
let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
ecx.write_scalar_at_offset_atomic(
@ -90,14 +90,14 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>(
fn mutex_get_id<'mir, 'tcx: 'mir>(
ecx: &MiriEvalContext<'mir, 'tcx>,
mutex_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, ScalarMaybeUninit<Provenance>> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
ecx.read_scalar_at_offset_atomic(mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed)
}
fn mutex_set_id<'mir, 'tcx: 'mir>(
ecx: &mut MiriEvalContext<'mir, 'tcx>,
mutex_op: &OpTy<'tcx, Provenance>,
id: impl Into<ScalarMaybeUninit<Provenance>>,
id: impl Into<Scalar<Provenance>>,
) -> InterpResult<'tcx, ()> {
ecx.write_scalar_at_offset_atomic(
mutex_op,
@ -119,13 +119,12 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>(
.atomic_compare_exchange_scalar(
&value_place,
&ImmTy::from_uint(0u32, ecx.machine.layouts.u32),
next_id.to_u32_scalar().into(),
next_id.to_u32_scalar(),
AtomicRwOrd::Relaxed,
AtomicReadOrd::Relaxed,
false,
)?
.to_scalar_pair()
.expect("compare_exchange returns a scalar pair");
.to_scalar_pair();
Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") {
// Caller of the closure needs to allocate next_id
@ -146,24 +145,10 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>(
fn rwlock_get_id<'mir, 'tcx: 'mir>(
ecx: &MiriEvalContext<'mir, 'tcx>,
rwlock_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, ScalarMaybeUninit<Provenance>> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
ecx.read_scalar_at_offset_atomic(rwlock_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed)
}
fn rwlock_set_id<'mir, 'tcx: 'mir>(
ecx: &mut MiriEvalContext<'mir, 'tcx>,
rwlock_op: &OpTy<'tcx, Provenance>,
id: impl Into<ScalarMaybeUninit<Provenance>>,
) -> InterpResult<'tcx, ()> {
ecx.write_scalar_at_offset_atomic(
rwlock_op,
4,
id,
layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32),
AtomicWriteOrd::Relaxed,
)
}
fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>(
ecx: &mut MiriEvalContext<'mir, 'tcx>,
rwlock_op: &OpTy<'tcx, Provenance>,
@ -175,13 +160,12 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>(
.atomic_compare_exchange_scalar(
&value_place,
&ImmTy::from_uint(0u32, ecx.machine.layouts.u32),
next_id.to_u32_scalar().into(),
next_id.to_u32_scalar(),
AtomicRwOrd::Relaxed,
AtomicReadOrd::Relaxed,
false,
)?
.to_scalar_pair()
.expect("compare_exchange returns a scalar pair");
.to_scalar_pair();
Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") {
// Caller of the closure needs to allocate next_id
@ -201,14 +185,14 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>(
fn condattr_get_clock_id<'mir, 'tcx: 'mir>(
ecx: &MiriEvalContext<'mir, 'tcx>,
attr_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, ScalarMaybeUninit<Provenance>> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32)
}
fn condattr_set_clock_id<'mir, 'tcx: 'mir>(
ecx: &mut MiriEvalContext<'mir, 'tcx>,
attr_op: &OpTy<'tcx, Provenance>,
clock_id: impl Into<ScalarMaybeUninit<Provenance>>,
clock_id: impl Into<Scalar<Provenance>>,
) -> InterpResult<'tcx, ()> {
ecx.write_scalar_at_offset(
attr_op,
@ -230,14 +214,14 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>(
fn cond_get_id<'mir, 'tcx: 'mir>(
ecx: &MiriEvalContext<'mir, 'tcx>,
cond_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, ScalarMaybeUninit<Provenance>> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
ecx.read_scalar_at_offset_atomic(cond_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed)
}
fn cond_set_id<'mir, 'tcx: 'mir>(
ecx: &mut MiriEvalContext<'mir, 'tcx>,
cond_op: &OpTy<'tcx, Provenance>,
id: impl Into<ScalarMaybeUninit<Provenance>>,
id: impl Into<Scalar<Provenance>>,
) -> InterpResult<'tcx, ()> {
ecx.write_scalar_at_offset_atomic(
cond_op,
@ -259,13 +243,12 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>(
.atomic_compare_exchange_scalar(
&value_place,
&ImmTy::from_uint(0u32, ecx.machine.layouts.u32),
next_id.to_u32_scalar().into(),
next_id.to_u32_scalar(),
AtomicRwOrd::Relaxed,
AtomicReadOrd::Relaxed,
false,
)?
.to_scalar_pair()
.expect("compare_exchange returns a scalar pair");
.to_scalar_pair();
Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") {
// Caller of the closure needs to allocate next_id
@ -279,14 +262,14 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>(
fn cond_get_clock_id<'mir, 'tcx: 'mir>(
ecx: &MiriEvalContext<'mir, 'tcx>,
cond_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, ScalarMaybeUninit<Provenance>> {
) -> InterpResult<'tcx, Scalar<Provenance>> {
ecx.read_scalar_at_offset(cond_op, 8, ecx.machine.layouts.i32)
}
fn cond_set_clock_id<'mir, 'tcx: 'mir>(
ecx: &mut MiriEvalContext<'mir, 'tcx>,
cond_op: &OpTy<'tcx, Provenance>,
clock_id: impl Into<ScalarMaybeUninit<Provenance>>,
clock_id: impl Into<Scalar<Provenance>>,
) -> InterpResult<'tcx, ()> {
ecx.write_scalar_at_offset(
cond_op,
@ -366,7 +349,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
let kind = this.read_scalar(kind_op)?.check_init()?;
let kind = this.read_scalar(kind_op)?;
if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? {
// In `glibc` implementation, the numeric values of
// `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal.
@ -407,7 +390,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let this = self.eval_context_mut();
// Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit.
mutexattr_get_kind(this, attr_op)?.check_init()?;
mutexattr_get_kind(this, attr_op)?;
// To catch double-destroys, we de-initialize the mutexattr.
// This is technically not right and might lead to false positives. For example, the below
@ -421,8 +404,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// However, the way libstd uses the pthread APIs works in our favor here, so we can get away with this.
// This can always be revisited to have some external state to catch double-destroys
// but not complain about the above code. See https://github.com/rust-lang/miri/pull/1933
mutexattr_set_kind(this, attr_op, ScalarMaybeUninit::Uninit)?;
this.write_uninit(&this.deref_operand(attr_op)?.into())?;
Ok(0)
}
@ -438,7 +420,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let kind = if this.ptr_is_null(attr)? {
this.eval_libc("PTHREAD_MUTEX_DEFAULT")?
} else {
mutexattr_get_kind(this, attr_op)?.check_init()?
mutexattr_get_kind(this, attr_op)?
};
// Write 0 to use the same code path as the static initializers.
@ -452,7 +434,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
fn pthread_mutex_lock(&mut self, mutex_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
let kind = mutex_get_kind(this, mutex_op)?.check_init()?;
let kind = mutex_get_kind(this, mutex_op)?;
let id = mutex_get_or_create_id(this, mutex_op)?;
let active_thread = this.get_active_thread();
@ -492,7 +474,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
let kind = mutex_get_kind(this, mutex_op)?.check_init()?;
let kind = mutex_get_kind(this, mutex_op)?;
let id = mutex_get_or_create_id(this, mutex_op)?;
let active_thread = this.get_active_thread();
@ -528,7 +510,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
let kind = mutex_get_kind(this, mutex_op)?.check_init()?;
let kind = mutex_get_kind(this, mutex_op)?;
let id = mutex_get_or_create_id(this, mutex_op)?;
let active_thread = this.get_active_thread();
@ -570,12 +552,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
// Destroying an uninit pthread_mutex is UB, so check to make sure it's not uninit.
mutex_get_kind(this, mutex_op)?.check_init()?;
mutex_get_id(this, mutex_op)?.check_init()?;
mutex_get_kind(this, mutex_op)?;
mutex_get_id(this, mutex_op)?;
// This might lead to false positives, see comment in pthread_mutexattr_destroy
mutex_set_kind(this, mutex_op, ScalarMaybeUninit::Uninit)?;
mutex_set_id(this, mutex_op, ScalarMaybeUninit::Uninit)?;
this.write_uninit(&this.deref_operand(mutex_op)?.into())?;
// FIXME: delete interpreter state associated with this mutex.
Ok(0)
@ -695,10 +676,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
// Destroying an uninit pthread_rwlock is UB, so check to make sure it's not uninit.
rwlock_get_id(this, rwlock_op)?.check_init()?;
rwlock_get_id(this, rwlock_op)?;
// This might lead to false positives, see comment in pthread_mutexattr_destroy
rwlock_set_id(this, rwlock_op, ScalarMaybeUninit::Uninit)?;
this.write_uninit(&this.deref_operand(rwlock_op)?.into())?;
// FIXME: delete interpreter state associated with this rwlock.
Ok(0)
@ -726,7 +707,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_mut();
let clock_id = this.read_scalar(clock_id_op)?.check_init()?;
let clock_id = this.read_scalar(clock_id_op)?;
if clock_id == this.eval_libc("CLOCK_REALTIME")?
|| clock_id == this.eval_libc("CLOCK_MONOTONIC")?
{
@ -759,10 +740,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let this = self.eval_context_mut();
// Destroying an uninit pthread_condattr is UB, so check to make sure it's not uninit.
condattr_get_clock_id(this, attr_op)?.check_init()?;
condattr_get_clock_id(this, attr_op)?;
// This might lead to false positives, see comment in pthread_mutexattr_destroy
condattr_set_clock_id(this, attr_op, ScalarMaybeUninit::Uninit)?;
this.write_uninit(&this.deref_operand(attr_op)?.into())?;
Ok(0)
}
@ -778,7 +759,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let clock_id = if this.ptr_is_null(attr)? {
this.eval_libc("CLOCK_REALTIME")?
} else {
condattr_get_clock_id(this, attr_op)?.check_init()?
condattr_get_clock_id(this, attr_op)?
};
// Write 0 to use the same code path as the static initializers.
@ -906,12 +887,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
// Destroying an uninit pthread_cond is UB, so check to make sure it's not uninit.
cond_get_id(this, cond_op)?.check_init()?;
cond_get_clock_id(this, cond_op)?.check_init()?;
cond_get_id(this, cond_op)?;
cond_get_clock_id(this, cond_op)?;
// This might lead to false positives, see comment in pthread_mutexattr_destroy
cond_set_id(this, cond_op, ScalarMaybeUninit::Uninit)?;
cond_set_clock_id(this, cond_op, ScalarMaybeUninit::Uninit)?;
this.write_uninit(&this.deref_operand(cond_op)?.into())?;
// FIXME: delete interpreter state associated with this condvar.
Ok(0)

View File

@ -112,7 +112,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
Dlsym::SetThreadDescription => {
let [handle, name] = check_arg_count(args)?;
let handle = this.read_scalar(handle)?.check_init()?;
let handle = this.read_scalar(handle)?;
let name = this.read_wide_str(this.read_pointer(name)?)?;

View File

@ -104,7 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
"SetLastError" => {
let [error] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let error = this.read_scalar(error)?.check_init()?;
let error = this.read_scalar(error)?;
this.set_last_error(error)?;
}
"GetLastError" => {
@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let key = u128::from(this.read_scalar(key)?.to_u32()?);
let active_thread = this.get_active_thread();
let new_data = this.read_scalar(new_ptr)?.check_init()?;
let new_data = this.read_scalar(new_ptr)?;
this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?;
// Return success (`1`).

View File

@ -158,7 +158,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
fn CloseHandle(&mut self, handle_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let handle = this.read_scalar(handle_op)?.check_init()?;
let handle = this.read_scalar(handle_op)?;
match Handle::from_scalar(handle, this)? {
Some(Handle::Thread(thread)) =>

View File

@ -14,13 +14,12 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>(
.atomic_compare_exchange_scalar(
&value_place,
&ImmTy::from_uint(0u32, ecx.machine.layouts.u32),
next_id.to_u32_scalar().into(),
next_id.to_u32_scalar(),
AtomicRwOrd::Relaxed,
AtomicReadOrd::Relaxed,
false,
)?
.to_scalar_pair()
.expect("compare_exchange returns a scalar pair");
.to_scalar_pair();
Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") {
// Caller of the closure needs to allocate next_id

View File

@ -20,14 +20,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let this = self.eval_context_mut();
let security = this.read_pointer(security_op)?;
// stacksize is ignored, but still needs to be a valid usize
this.read_scalar(stacksize_op)?.to_machine_usize(this)?;
let start_routine = this.read_pointer(start_op)?;
let func_arg = this.read_immediate(arg_op)?;
let flags = this.read_scalar(flags_op)?.to_u32()?;
let thread = if this.ptr_is_null(this.read_pointer(thread_op)?)? {
@ -66,8 +62,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
) -> InterpResult<'tcx, u32> {
let this = self.eval_context_mut();
let handle = this.read_scalar(handle_op)?.check_init()?;
let handle = this.read_scalar(handle_op)?;
let timeout = this.read_scalar(timeout_op)?.to_u32()?;
let thread = match Handle::from_scalar(handle, this)? {

View File

@ -3,6 +3,6 @@
//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation
fn main() {
let i = unsafe { std::mem::MaybeUninit::<i32>::uninit().assume_init() };
let _x = i + 0; //~ ERROR: this operation requires initialized memory
let i = unsafe { std::mem::MaybeUninit::<i32>::uninit().assume_init() }; //~ ERROR: uninitialized
let _x = i + 0;
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
--> $DIR/invalid_int.rs:LL:CC
|
LL | let _x = i + 0;
| ^^^^^ using uninitialized data, but this operation requires initialized memory
LL | let i = unsafe { std::mem::MaybeUninit::<i32>::uninit().assume_init() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected initialized bytes
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
--> $DIR/transmute-pair-uninit.rs:LL:CC
|
LL | let v = unsafe { *z.offset(first_undef) };
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes
| ^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected initialized bytes
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
--> $DIR/uninit_byte_read.rs:LL:CC
|
LL | let undef = unsafe { *v.get_unchecked(5) };
| ^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes
| ^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -6,5 +6,5 @@ union MyUninit {
}
fn main() {
let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: encountered uninitialized bytes, but expected a boolean
let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected a boolean
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
--> $DIR/invalid_bool_uninit.rs:LL:CC
|
LL | let _b = unsafe { MyUninit { init: () }.uninit };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a boolean
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -6,5 +6,5 @@ union MyUninit {
}
fn main() {
let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: encountered uninitialized bytes, but expected a valid unicode scalar value
let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`)
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
--> $DIR/invalid_char_uninit.rs:LL:CC
|
LL | let _b = unsafe { MyUninit { init: () }.uninit };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -6,5 +6,5 @@ union MyUninit {
}
fn main() {
let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: encountered uninitialized bytes
let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected a proper pointer or integer value
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
--> $DIR/invalid_fnptr_uninit.rs:LL:CC
|
LL | let _b = unsafe { MyUninit { init: () }.uninit };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a proper pointer or integer value
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -4,5 +4,5 @@
fn main() {
// Deliberately using `mem::uninitialized` to make sure that despite all the mitigations, we consider this UB.
let _val: f32 = unsafe { std::mem::uninitialized() };
//~^ ERROR: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes
//~^ ERROR: uninitialized
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
--> $DIR/uninit_float.rs:LL:CC
|
LL | let _val: f32 = unsafe { std::mem::uninitialized() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes
| ^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -2,5 +2,5 @@
fn main() {
let _val = unsafe { std::mem::MaybeUninit::<usize>::uninit().assume_init() };
//~^ ERROR: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes
//~^ ERROR: uninitialized
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
--> $DIR/uninit_integer.rs:LL:CC
|
LL | let _val = unsafe { std::mem::MaybeUninit::<usize>::uninit().assume_init() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,4 +1,4 @@
fn main() {
let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() };
//~^ ERROR: constructing invalid value at .value: encountered uninitialized raw pointer
//~^ ERROR: uninitialized
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized raw pointer
error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
--> $DIR/uninit_raw_ptr.rs:LL:CC
|
LL | let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized raw pointer
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View File

@ -1,16 +0,0 @@
//@compile-flags: -Zmiri-disable-validation
use std::mem::MaybeUninit;
fn main() {
unsafe {
let mut x = MaybeUninit::<i64>::uninit();
// Put in a ptr.
x.as_mut_ptr().cast::<&i32>().write_unaligned(&0);
// Overwrite parts of that pointer with 'uninit' through a Scalar.
let ptr = x.as_mut_ptr().cast::<i32>();
*ptr = MaybeUninit::uninit().assume_init();
// Reading this back should hence work fine.
let _c = *ptr;
}
}