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:
commit
bb8212484f
@ -1 +1 @@
|
||||
e1b28cd2f16bd5b832183d7968cae3bb9213e78d
|
||||
4065b89b1e7287047d7d6c65e7abd7b8ee70bcf0
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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`
|
||||
|
@ -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
|
||||
|
@ -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) =
|
||||
|
@ -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> {
|
||||
|
@ -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(),
|
||||
|
@ -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()?)),
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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)?;
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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)?;
|
||||
}
|
||||
|
||||
|
@ -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")?;
|
||||
|
@ -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)?;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)?)?;
|
||||
|
||||
|
@ -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`).
|
||||
|
@ -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)) =>
|
||||
|
@ -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
|
||||
|
@ -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)? {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user