Auto merge of #114333 - RalfJung:dangling-ptr-offset, r=oli-obk

Miri: fix error on dangling pointer inbounds offset

We used to claim that the pointer was "dereferenced", but that is just not true.

Can be reviewed commit-by-commit. The first commit is an unrelated rename that didn't seem worth splitting into its own PR.

r? `@oli-obk`
This commit is contained in:
bors 2023-08-02 09:12:32 +00:00
commit 64ad036307
69 changed files with 214 additions and 207 deletions

View File

@ -282,7 +282,7 @@ const_eval_pointer_out_of_bounds =
*[many] bytes
} starting at offset {$ptr_offset} is out-of-bounds
const_eval_pointer_use_after_free =
pointer to {$allocation} was dereferenced after this allocation got freed
{$bad_pointer_message}: {$alloc_id} has been freed, so this pointer is dangling
const_eval_ptr_as_bytes_1 =
this code performed an operation that depends on the underlying bytes representing a pointer
const_eval_ptr_as_bytes_2 =

View File

@ -214,9 +214,9 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
// &str or &&str
assert!(args.len() == 1);
let mut msg_place = self.deref_operand(&args[0])?;
let mut msg_place = self.deref_pointer(&args[0])?;
while msg_place.layout.ty.is_ref() {
msg_place = self.deref_operand(&msg_place)?;
msg_place = self.deref_pointer(&msg_place)?;
}
let msg = Symbol::intern(self.read_str(&msg_place)?);

View File

@ -102,7 +102,7 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
ty::FnPtr(_) | ty::RawPtr(_) => Err(ValTreeCreationError::NonSupportedType),
ty::Ref(_, _, _) => {
let Ok(derefd_place)= ecx.deref_operand(place) else {
let Ok(derefd_place)= ecx.deref_pointer(place) else {
return Err(ValTreeCreationError::Other);
};
debug!(?derefd_place);

View File

@ -492,7 +492,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
InvalidMeta(InvalidMetaKind::SliceTooBig) => const_eval_invalid_meta_slice,
InvalidMeta(InvalidMetaKind::TooBig) => const_eval_invalid_meta,
UnterminatedCString(_) => const_eval_unterminated_c_string,
PointerUseAfterFree(_) => const_eval_pointer_use_after_free,
PointerUseAfterFree(_, _) => const_eval_pointer_use_after_free,
PointerOutOfBounds { ptr_size: Size::ZERO, .. } => const_eval_zst_pointer_out_of_bounds,
PointerOutOfBounds { .. } => const_eval_pointer_out_of_bounds,
DanglingIntPointer(0, _) => const_eval_dangling_null_pointer,
@ -545,8 +545,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
builder.set_arg("pointer", ptr);
}
PointerUseAfterFree(allocation) => {
builder.set_arg("allocation", allocation);
PointerUseAfterFree(alloc_id, msg) => {
builder
.set_arg("alloc_id", alloc_id)
.set_arg("bad_pointer_message", bad_pointer_message(msg, handler));
}
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
builder

View File

@ -144,7 +144,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
sym::min_align_of_val | sym::size_of_val => {
// Avoid `deref_operand` -- this is not a deref, the ptr does not have to be
// Avoid `deref_pointer` -- this is not a deref, the ptr does not have to be
// dereferenceable!
let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?;
let (size, align) = self
@ -225,7 +225,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.write_scalar(val, dest)?;
}
sym::discriminant_value => {
let place = self.deref_operand(&args[0])?;
let place = self.deref_pointer(&args[0])?;
let variant = self.read_discriminant(&place)?;
let discr = self.discriminant_for_variant(place.layout, variant)?;
self.write_scalar(discr, dest)?;

View File

@ -317,7 +317,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
kind = "static_mem"
)
}
None => err_ub!(PointerUseAfterFree(alloc_id)),
None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccessTest)),
}
.into());
};
@ -380,7 +380,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
M::enforce_alignment(self),
CheckInAllocMsg::MemoryAccessTest,
|alloc_id, offset, prov| {
let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
let (size, align) = self
.get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?;
Ok((size, align, (alloc_id, offset, prov)))
},
)
@ -404,7 +405,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
CheckAlignment::Error,
msg,
|alloc_id, _, _| {
let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
let (size, align) = self.get_live_alloc_size_and_align(alloc_id, msg)?;
Ok((size, align, ()))
},
)?;
@ -414,7 +415,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Low-level helper function to check if a ptr is in-bounds and potentially return a reference
/// to the allocation it points to. Supports both shared and mutable references, as the actual
/// checking is offloaded to a helper closure. `align` defines whether and which alignment check
/// is done. Returns `None` for size 0, and otherwise `Some` of what `alloc_size` returned.
/// is done.
///
/// If this returns `None`, the size is 0; it can however return `Some` even for size 0.
fn check_and_deref_ptr<T>(
&self,
ptr: Pointer<Option<M::Provenance>>,
@ -515,7 +518,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
Some(GlobalAlloc::Function(..)) => throw_ub!(DerefFunctionPointer(id)),
Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)),
None => throw_ub!(PointerUseAfterFree(id)),
None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccessTest)),
Some(GlobalAlloc::Static(def_id)) => {
assert!(self.tcx.is_static(def_id));
assert!(!self.tcx.is_thread_local_static(def_id));
@ -761,11 +764,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
}
/// Obtain the size and alignment of a live allocation.
pub fn get_live_alloc_size_and_align(&self, id: AllocId) -> InterpResult<'tcx, (Size, Align)> {
/// Obtain the size and alignment of a *live* allocation.
fn get_live_alloc_size_and_align(
&self,
id: AllocId,
msg: CheckInAllocMsg,
) -> InterpResult<'tcx, (Size, Align)> {
let (size, align, kind) = self.get_alloc_info(id);
if matches!(kind, AllocKind::Dead) {
throw_ub!(PointerUseAfterFree(id))
throw_ub!(PointerUseAfterFree(id, msg))
}
Ok((size, align))
}

View File

@ -419,7 +419,7 @@ where
///
/// Only call this if you are sure the place is "valid" (aligned and inbounds), or do not
/// want to ever use the place for memory access!
/// Generally prefer `deref_operand`.
/// Generally prefer `deref_pointer`.
pub fn ref_to_mplace(
&self,
val: &ImmTy<'tcx, M::Provenance>,
@ -439,8 +439,9 @@ where
}
/// Take an operand, representing a pointer, and dereference it to a place.
/// Corresponds to the `*` operator in Rust.
#[instrument(skip(self), level = "debug")]
pub fn deref_operand(
pub fn deref_pointer(
&self,
src: &impl Readable<'tcx, M::Provenance>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {

View File

@ -290,7 +290,7 @@ where
OpaqueCast(ty) => base.transmute(self.layout_of(ty)?, self)?,
Field(field, _) => self.project_field(base, field.index())?,
Downcast(_, variant) => self.project_downcast(base, variant)?,
Deref => self.deref_operand(&base.to_op(self)?)?.into(),
Deref => self.deref_pointer(&base.to_op(self)?)?.into(),
Index(local) => {
let layout = self.layout_of(self.tcx.types.usize)?;
let n = self.local_to_op(self.frame(), local, Some(layout))?;

View File

@ -224,8 +224,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Len(place) => {
let src = self.eval_place(place)?;
let op = self.place_to_op(&src)?;
let len = op.len(self)?;
let len = src.len(self)?;
self.write_scalar(Scalar::from_target_usize(len, self), &dest)?;
}

View File

@ -661,7 +661,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let receiver_place = loop {
match receiver.layout.ty.kind() {
ty::Ref(..) | ty::RawPtr(..) => {
// We do *not* use `deref_operand` here: we don't want to conceptually
// We do *not* use `deref_pointer` here: we don't want to conceptually
// create a place that must be dereferenceable, since the receiver might
// be a raw pointer and (for `*const dyn Trait`) we don't need to
// actually access memory to resolve this method.

View File

@ -345,6 +345,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
value: &OpTy<'tcx, M::Provenance>,
ptr_kind: PointerKind,
) -> InterpResult<'tcx> {
// Not using `deref_pointer` since we do the dereferenceable check ourselves below.
let place = self.ecx.ref_to_mplace(&self.read_immediate(value, ptr_kind.into())?)?;
// Handle wide pointers.
// Check metadata early, for better diagnostics
@ -515,9 +516,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
Ok(true)
}
ty::RawPtr(..) => {
// We are conservative with uninit for integers, but try to
// actually enforce the strict rules for raw pointers (mostly because
// that lets us re-use `ref_to_mplace`).
let place =
self.ecx.ref_to_mplace(&self.read_immediate(value, ExpectedKind::RawPtr)?)?;
if place.layout.is_unsized() {

View File

@ -282,8 +282,8 @@ pub enum UndefinedBehaviorInfo<'a> {
InvalidMeta(InvalidMetaKind),
/// Reading a C string that does not end within its allocation.
UnterminatedCString(Pointer),
/// Dereferencing a dangling pointer after it got freed.
PointerUseAfterFree(AllocId),
/// Using a pointer after it got freed.
PointerUseAfterFree(AllocId, CheckInAllocMsg),
/// Used a pointer outside the bounds it is valid for.
/// (If `ptr_size > 0`, determines the size of the memory range that was expected to be in-bounds.)
PointerOutOfBounds {

View File

@ -18,7 +18,7 @@ use rustc_middle::ty::{
layout::{HasParamEnv, LayoutOf},
Ty,
};
use rustc_target::abi::{Abi, Size};
use rustc_target::abi::{Abi, Align, Size};
use crate::borrow_tracker::{
stacked_borrows::diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder},
@ -619,6 +619,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
retag_info: RetagInfo, // diagnostics info about this retag
) -> InterpResult<'tcx, Option<AllocId>> {
let this = self.eval_context_mut();
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
this.check_ptr_access_align(place.ptr, size, Align::ONE, CheckInAllocMsg::InboundsTest)?;
// It is crucial that this gets called on all code paths, to ensure we track tag creation.
let log_creation = |this: &MiriInterpCx<'mir, 'tcx>,
@ -707,18 +709,6 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?;
log_creation(this, Some((alloc_id, base_offset, orig_tag)))?;
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
let (alloc_size, _) = this.get_live_alloc_size_and_align(alloc_id)?;
if base_offset + size > alloc_size {
throw_ub!(PointerOutOfBounds {
alloc_id,
alloc_size,
ptr_offset: this.target_usize_to_isize(base_offset.bytes()),
ptr_size: size,
msg: CheckInAllocMsg::InboundsTest
});
}
trace!(
"reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}",
new_tag,

View File

@ -1,6 +1,6 @@
use log::trace;
use rustc_target::abi::{Abi, Size};
use rustc_target::abi::{Abi, Align, Size};
use crate::borrow_tracker::{AccessKind, GlobalStateInner, ProtectorKind, RetagFields};
use rustc_middle::{
@ -182,6 +182,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
new_tag: BorTag,
) -> InterpResult<'tcx, Option<(AllocId, BorTag)>> {
let this = self.eval_context_mut();
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
this.check_ptr_access_align(place.ptr, ptr_size, Align::ONE, CheckInAllocMsg::InboundsTest)?;
// It is crucial that this gets called on all code paths, to ensure we track tag creation.
let log_creation = |this: &MiriInterpCx<'mir, 'tcx>,
@ -202,12 +204,14 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
};
trace!("Reborrow of size {:?}", ptr_size);
let (alloc_id, base_offset, parent_prov) = if ptr_size > Size::ZERO {
this.ptr_get_alloc_id(place.ptr)?
} else {
match this.ptr_try_get_alloc_id(place.ptr) {
Ok(data) => data,
let (alloc_id, base_offset, parent_prov) = match this.ptr_try_get_alloc_id(place.ptr) {
Ok(data) => {
// Unlike SB, we *do* a proper retag for size 0 if can identify the allocation.
// After all, the pointer may be lazily initialized outside this initial range.
data
},
Err(_) => {
assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here
// This pointer doesn't come with an AllocId, so there's no
// memory to do retagging in.
trace!(
@ -219,34 +223,14 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
log_creation(this, None)?;
return Ok(None);
}
}
};
log_creation(this, Some((alloc_id, base_offset, parent_prov)))?;
let orig_tag = match parent_prov {
ProvenanceExtra::Wildcard => return Ok(None), // TODO: handle wildcard pointers
ProvenanceExtra::Concrete(tag) => tag,
};
// Protection against trying to get a reference to a vtable:
// vtables do not have an alloc_extra so the call to
// `get_alloc_extra` that follows fails.
let (alloc_size, _align, alloc_kind) = this.get_alloc_info(alloc_id);
if ptr_size == Size::ZERO && !matches!(alloc_kind, AllocKind::LiveData) {
return Ok(Some((alloc_id, orig_tag)));
}
log_creation(this, Some((alloc_id, base_offset, parent_prov)))?;
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
if base_offset + ptr_size > alloc_size {
throw_ub!(PointerOutOfBounds {
alloc_id,
alloc_size,
ptr_offset: this.target_usize_to_isize(base_offset.bytes()),
ptr_size,
msg: CheckInAllocMsg::InboundsTest
});
}
trace!(
"reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}",
new_tag,

View File

@ -206,7 +206,7 @@ pub(super) trait EvalContextExtPriv<'mir, 'tcx: 'mir>:
) -> InterpResult<'tcx, Option<Id>> {
let this = self.eval_context_mut();
let value_place =
this.deref_operand_and_offset(lock_op, offset, lock_layout, this.machine.layouts.u32)?;
this.deref_pointer_and_offset(lock_op, offset, lock_layout, this.machine.layouts.u32)?;
// Since we are lazy, this update has to be atomic.
let (old, success) = this

View File

@ -715,9 +715,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
/// Dereference a pointer operand to a place using `layout` instead of the pointer's declared type
fn deref_operand_as(
fn deref_pointer_as(
&self,
op: &OpTy<'tcx, Provenance>,
op: &impl Readable<'tcx, Provenance>,
layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
let this = self.eval_context_ref();
@ -746,15 +746,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
/// Calculates the MPlaceTy given the offset and layout of an access on an operand
fn deref_operand_and_offset(
fn deref_pointer_and_offset(
&self,
op: &OpTy<'tcx, Provenance>,
op: &impl Readable<'tcx, Provenance>,
offset: u64,
base_layout: TyAndLayout<'tcx>,
value_layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
let this = self.eval_context_ref();
let op_place = this.deref_operand_as(op, base_layout)?;
let op_place = this.deref_pointer_as(op, base_layout)?;
let offset = Size::from_bytes(offset);
// Ensure that the access is within bounds.
@ -763,28 +763,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
Ok(value_place)
}
fn read_scalar_at_offset(
fn deref_pointer_and_read(
&self,
op: &OpTy<'tcx, Provenance>,
op: &impl Readable<'tcx, Provenance>,
offset: u64,
base_layout: TyAndLayout<'tcx>,
value_layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, Scalar<Provenance>> {
let this = self.eval_context_ref();
let value_place = this.deref_operand_and_offset(op, offset, base_layout, value_layout)?;
let value_place = this.deref_pointer_and_offset(op, offset, base_layout, value_layout)?;
this.read_scalar(&value_place)
}
fn write_scalar_at_offset(
fn deref_pointer_and_write(
&mut self,
op: &OpTy<'tcx, Provenance>,
op: &impl Readable<'tcx, Provenance>,
offset: u64,
value: impl Into<Scalar<Provenance>>,
base_layout: TyAndLayout<'tcx>,
value_layout: TyAndLayout<'tcx>,
) -> InterpResult<'tcx, ()> {
let this = self.eval_context_mut();
let value_place = this.deref_operand_and_offset(op, offset, base_layout, value_layout)?;
let value_place = this.deref_pointer_and_offset(op, offset, base_layout, value_layout)?;
this.write_scalar(value, &value_place)
}

View File

@ -97,7 +97,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
1 => {
let [_flags, buf] = this.check_shim(abi, Abi::Rust, link_name, args)?;
let buf_place = this.deref_operand(buf)?;
let buf_place = this.deref_pointer(buf)?;
let ptr_layout = this.layout_of(ptr_ty)?;

View File

@ -418,9 +418,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// // First thing: load all the arguments. Details depend on the shim.
// let arg1 = this.read_scalar(arg1)?.to_u32()?;
// let arg2 = this.read_pointer(arg2)?; // when you need to work with the pointer directly
// let arg3 = this.deref_operand_as(arg3, this.libc_ty_layout("some_libc_struct"))?; // when you want to load/store
// let arg3 = this.deref_pointer_as(arg3, this.libc_ty_layout("some_libc_struct"))?; // when you want to load/store
// // through the pointer and supply the type information yourself
// let arg4 = this.deref_operand(arg4)?; // when you want to load/store through the pointer and trust
// let arg4 = this.deref_pointer(arg4)?; // when you want to load/store through the pointer and trust
// // the user-given type (which you shouldn't usually do)
//
// // ...

View File

@ -130,7 +130,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
let this = self.eval_context_mut();
let [place] = check_arg_count(args)?;
let place = this.deref_operand(place)?;
let place = this.deref_pointer(place)?;
// Perform atomic load.
let val = this.read_scalar_atomic(&place, atomic)?;
@ -147,7 +147,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
let this = self.eval_context_mut();
let [place, val] = check_arg_count(args)?;
let place = this.deref_operand(place)?;
let place = this.deref_pointer(place)?;
// Perform regular load.
let val = this.read_scalar(val)?;
@ -188,7 +188,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
let this = self.eval_context_mut();
let [place, rhs] = check_arg_count(args)?;
let place = this.deref_operand(place)?;
let place = this.deref_pointer(place)?;
let rhs = this.read_immediate(rhs)?;
if !place.layout.ty.is_integral() && !place.layout.ty.is_unsafe_ptr() {
@ -229,7 +229,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
let this = self.eval_context_mut();
let [place, new] = check_arg_count(args)?;
let place = this.deref_operand(place)?;
let place = this.deref_pointer(place)?;
let new = this.read_scalar(new)?;
let old = this.atomic_exchange_scalar(&place, new, atomic)?;
@ -248,7 +248,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
let this = self.eval_context_mut();
let [place, expect_old, new] = check_arg_count(args)?;
let place = this.deref_operand(place)?;
let place = this.deref_pointer(place)?;
let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()`
let new = this.read_scalar(new)?;

View File

@ -96,12 +96,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Raw memory accesses
"volatile_load" => {
let [place] = check_arg_count(args)?;
let place = this.deref_operand(place)?;
let place = this.deref_pointer(place)?;
this.copy_op(&place, dest, /*allow_transmute*/ false)?;
}
"volatile_store" => {
let [place, dest] = check_arg_count(args)?;
let place = this.deref_operand(place)?;
let place = this.deref_pointer(place)?;
this.copy_op(dest, &place, /*allow_transmute*/ false)?;
}

View File

@ -534,7 +534,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let dest = this.project_index(&dest, i)?;
let val = if simd_element_to_bool(mask)? {
let place = this.deref_operand(&ptr)?;
let place = this.deref_pointer(&ptr)?;
this.read_immediate(&place)?
} else {
passthru
@ -557,7 +557,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let mask = this.read_immediate(&this.project_index(&mask, i)?)?;
if simd_element_to_bool(mask)? {
let place = this.deref_operand(&ptr)?;
let place = this.deref_pointer(&ptr)?;
this.write_immediate(*value, &place)?;
}
}

View File

@ -25,7 +25,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.assert_target_os_is_unix("clock_gettime");
let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
let tp = this.deref_operand_as(tp_op, this.libc_ty_layout("timespec"))?;
let tp = this.deref_pointer_as(tp_op, this.libc_ty_layout("timespec"))?;
let absolute_clocks;
let mut relative_clocks;
@ -92,7 +92,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.assert_target_os_is_unix("gettimeofday");
this.check_no_isolation("`gettimeofday`")?;
let tv = this.deref_operand_as(tv_op, this.libc_ty_layout("timeval"))?;
let tv = this.deref_pointer_as(tv_op, this.libc_ty_layout("timeval"))?;
// Using tz is obsolete and should always be null
let tz = this.read_pointer(tz_op)?;
@ -121,7 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.assert_target_os("windows", "GetSystemTimeAsFileTime");
this.check_no_isolation("`GetSystemTimeAsFileTime`")?;
let filetime = this.deref_operand_as(LPFILETIME_op, this.windows_ty_layout("FILETIME"))?;
let filetime = this.deref_pointer_as(LPFILETIME_op, this.windows_ty_layout("FILETIME"))?;
let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC");
let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC");
@ -156,7 +156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let qpc = i64::try_from(duration.as_nanos()).map_err(|_| {
err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported")
})?;
this.write_scalar(Scalar::from_i64(qpc), &this.deref_operand(lpPerformanceCount_op)?)?;
this.write_scalar(Scalar::from_i64(qpc), &this.deref_pointer(lpPerformanceCount_op)?)?;
Ok(Scalar::from_i32(-1)) // return non-zero on success
}
@ -176,7 +176,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// and thus 10^9 counts per second.
this.write_scalar(
Scalar::from_i64(1_000_000_000),
&this.deref_operand_as(lpFrequency_op, this.machine.layouts.u64)?,
&this.deref_pointer_as(lpFrequency_op, this.machine.layouts.u64)?,
)?;
Ok(Scalar::from_i32(-1)) // Return non-zero on success
}
@ -203,7 +203,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.assert_target_os("macos", "mach_timebase_info");
let info = this.deref_operand_as(info_op, this.libc_ty_layout("mach_timebase_info"))?;
let info = this.deref_pointer_as(info_op, this.libc_ty_layout("mach_timebase_info"))?;
// Since our emulated ticks in `mach_absolute_time` *are* nanoseconds,
// no scaling needs to happen.
@ -222,7 +222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.assert_target_os_is_unix("nanosleep");
let req = this.deref_operand_as(req_op, this.libc_ty_layout("timespec"))?;
let req = this.deref_pointer_as(req_op, this.libc_ty_layout("timespec"))?;
let duration = match this.read_timespec(&req)? {
Some(duration) => duration,

View File

@ -191,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Allocation
"posix_memalign" => {
let [ret, align, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let ret = this.deref_operand(ret)?;
let ret = this.deref_pointer(ret)?;
let align = this.read_target_usize(align)?;
let size = this.read_target_usize(size)?;
// Align must be power of 2, and also at least ptr-sized (POSIX rules).
@ -271,7 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Thread-local storage
"pthread_key_create" => {
let [key, dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let key_place = this.deref_operand_as(key, this.libc_ty_layout("pthread_key_t"))?;
let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?;
let dtor = this.read_pointer(dtor)?;
// Extract the function type out of the signature (that seems easier than constructing it ourselves).
@ -506,7 +506,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
"pthread_attr_getguardsize"
if this.frame_in_std() => {
let [_attr, guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let guard_size = this.deref_operand(guard_size)?;
let guard_size = this.deref_pointer(guard_size)?;
let guard_size_layout = this.libc_ty_layout("size_t");
this.write_scalar(Scalar::from_uint(this.machine.page_size, guard_size_layout.size), &guard_size)?;
@ -532,9 +532,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Hence we can mostly ignore the input `attr_place`.
let [attr_place, addr_place, size_place] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let _attr_place = this.deref_operand_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
let addr_place = this.deref_operand(addr_place)?;
let size_place = this.deref_operand(size_place)?;
let _attr_place = this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?;
let addr_place = this.deref_pointer(addr_place)?;
let size_place = this.deref_pointer(size_place)?;
this.write_scalar(
Scalar::from_uint(this.machine.stack_addr, this.pointer_size()),
@ -575,10 +575,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.check_no_isolation("`getpwuid_r`")?;
let uid = this.read_scalar(uid)?.to_u32()?;
let pwd = this.deref_operand_as(pwd, this.libc_ty_layout("passwd"))?;
let pwd = this.deref_pointer_as(pwd, this.libc_ty_layout("passwd"))?;
let buf = this.read_pointer(buf)?;
let buflen = this.read_target_usize(buflen)?;
let result = this.deref_operand(result)?;
let result = this.deref_pointer(result)?;
// Must be for "us".
if uid != crate::shims::unix::UID {

View File

@ -344,7 +344,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx
let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0));
let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0));
let buf = this.deref_operand_as(buf_op, this.libc_ty_layout("stat"))?;
let buf = this.deref_pointer_as(buf_op, this.libc_ty_layout("stat"))?;
this.write_int_fields_named(
&[
@ -1014,7 +1014,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
return Ok(-1);
}
let statxbuf = this.deref_operand_as(statxbuf_op, this.libc_ty_layout("statx"))?;
let statxbuf = this.deref_pointer_as(statxbuf_op, this.libc_ty_layout("statx"))?;
let path = this.read_path_from_c_str(pathname_ptr)?.into_owned();
// See <https://github.com/rust-lang/rust/pull/79196> for a discussion of argument sizes.
@ -1420,7 +1420,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// pub d_name: [c_char; 1024],
// }
let entry_place = this.deref_operand_as(entry_op, this.libc_ty_layout("dirent"))?;
let entry_place = this.deref_pointer_as(entry_op, this.libc_ty_layout("dirent"))?;
let name_place = this.project_field(&entry_place, 5)?;
let file_name = dir_entry.file_name(); // not a Path as there are no separators!
@ -1456,14 +1456,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
&entry_place,
)?;
let result_place = this.deref_operand(result_op)?;
let result_place = this.deref_pointer(result_op)?;
this.write_scalar(this.read_scalar(entry_op)?, &result_place)?;
0
}
None => {
// end of stream: return 0, assign *result=NULL
this.write_null(&this.deref_operand(result_op)?)?;
this.write_null(&this.deref_pointer(result_op)?)?;
0
}
Some(Err(e)) =>

View File

@ -71,7 +71,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let epoll_ctl_del = this.eval_libc_i32("EPOLL_CTL_DEL");
if op == epoll_ctl_add || op == epoll_ctl_mod {
let event = this.deref_operand_as(event, this.libc_ty_layout("epoll_event"))?;
let event = this.deref_pointer_as(event, this.libc_ty_layout("epoll_event"))?;
let events = this.project_field(&event, 0)?;
let events = this.read_scalar(&events)?.to_u32()?;
@ -240,7 +240,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let _domain = this.read_scalar(domain)?.to_i32()?;
let _type_ = this.read_scalar(type_)?.to_i32()?;
let _protocol = this.read_scalar(protocol)?.to_i32()?;
let sv = this.deref_operand(sv)?;
let sv = this.deref_pointer(sv)?;
let fh = &mut this.machine.file_handler;
let sv0 = fh.insert_fd(Box::new(SocketPair));

View File

@ -198,7 +198,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
this.read_scalar(pid)?.to_i32()?;
this.read_target_usize(cpusetsize)?;
this.deref_operand_as(mask, this.libc_ty_layout("cpu_set_t"))?;
this.deref_pointer_as(mask, this.libc_ty_layout("cpu_set_t"))?;
// FIXME: we just return an error; `num_cpus` then falls back to `sysconf`.
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;

View File

@ -130,7 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.check_no_isolation("`_NSGetExecutablePath`")?;
let buf_ptr = this.read_pointer(buf)?;
let bufsize = this.deref_operand(bufsize)?;
let bufsize = this.deref_pointer(bufsize)?;
// Using the host current_exe is a bit off, but consistent with Linux
// (where stdlib reads /proc/self/exe).

View File

@ -36,7 +36,7 @@ fn mutexattr_get_kind<'mir, 'tcx: 'mir>(
ecx: &MiriInterpCx<'mir, 'tcx>,
attr_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, i32> {
ecx.read_scalar_at_offset(
ecx.deref_pointer_and_read(
attr_op,
0,
ecx.libc_ty_layout("pthread_mutexattr_t"),
@ -50,7 +50,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>(
attr_op: &OpTy<'tcx, Provenance>,
kind: i32,
) -> InterpResult<'tcx, ()> {
ecx.write_scalar_at_offset(
ecx.deref_pointer_and_write(
attr_op,
0,
Scalar::from_i32(kind),
@ -79,7 +79,7 @@ fn mutex_reset_id<'mir, 'tcx: 'mir>(
ecx: &mut MiriInterpCx<'mir, 'tcx>,
mutex_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, ()> {
ecx.write_scalar_at_offset(
ecx.deref_pointer_and_write(
mutex_op,
4,
Scalar::from_i32(0),
@ -93,7 +93,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>(
mutex_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, i32> {
let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
ecx.read_scalar_at_offset(
ecx.deref_pointer_and_read(
mutex_op,
offset,
ecx.libc_ty_layout("pthread_mutex_t"),
@ -108,7 +108,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>(
kind: i32,
) -> InterpResult<'tcx, ()> {
let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
ecx.write_scalar_at_offset(
ecx.deref_pointer_and_write(
mutex_op,
offset,
Scalar::from_i32(kind),
@ -141,7 +141,7 @@ fn condattr_get_clock_id<'mir, 'tcx: 'mir>(
ecx: &MiriInterpCx<'mir, 'tcx>,
attr_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, i32> {
ecx.read_scalar_at_offset(
ecx.deref_pointer_and_read(
attr_op,
0,
ecx.libc_ty_layout("pthread_condattr_t"),
@ -155,7 +155,7 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>(
attr_op: &OpTy<'tcx, Provenance>,
clock_id: i32,
) -> InterpResult<'tcx, ()> {
ecx.write_scalar_at_offset(
ecx.deref_pointer_and_write(
attr_op,
0,
Scalar::from_i32(clock_id),
@ -184,7 +184,7 @@ fn cond_reset_id<'mir, 'tcx: 'mir>(
ecx: &mut MiriInterpCx<'mir, 'tcx>,
cond_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, ()> {
ecx.write_scalar_at_offset(
ecx.deref_pointer_and_write(
cond_op,
4,
Scalar::from_i32(0),
@ -197,7 +197,7 @@ fn cond_get_clock_id<'mir, 'tcx: 'mir>(
ecx: &MiriInterpCx<'mir, 'tcx>,
cond_op: &OpTy<'tcx, Provenance>,
) -> InterpResult<'tcx, i32> {
ecx.read_scalar_at_offset(
ecx.deref_pointer_and_read(
cond_op,
8,
ecx.libc_ty_layout("pthread_cond_t"),
@ -211,7 +211,7 @@ fn cond_set_clock_id<'mir, 'tcx: 'mir>(
cond_op: &OpTy<'tcx, Provenance>,
clock_id: i32,
) -> InterpResult<'tcx, ()> {
ecx.write_scalar_at_offset(
ecx.deref_pointer_and_write(
cond_op,
8,
Scalar::from_i32(clock_id),
@ -346,7 +346,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// 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
this.write_uninit(
&this.deref_operand_as(attr_op, this.libc_ty_layout("pthread_mutexattr_t"))?,
&this.deref_pointer_as(attr_op, this.libc_ty_layout("pthread_mutexattr_t"))?,
)?;
Ok(0)
@ -500,7 +500,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// This might lead to false positives, see comment in pthread_mutexattr_destroy
this.write_uninit(
&this.deref_operand_as(mutex_op, this.libc_ty_layout("pthread_mutex_t"))?,
&this.deref_pointer_as(mutex_op, this.libc_ty_layout("pthread_mutex_t"))?,
)?;
// FIXME: delete interpreter state associated with this mutex.
@ -625,7 +625,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// This might lead to false positives, see comment in pthread_mutexattr_destroy
this.write_uninit(
&this.deref_operand_as(rwlock_op, this.libc_ty_layout("pthread_rwlock_t"))?,
&this.deref_pointer_as(rwlock_op, this.libc_ty_layout("pthread_rwlock_t"))?,
)?;
// FIXME: delete interpreter state associated with this rwlock.
@ -675,7 +675,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let this = self.eval_context_mut();
let clock_id = condattr_get_clock_id(this, attr_op)?;
this.write_scalar(Scalar::from_i32(clock_id), &this.deref_operand(clk_id_op)?)?;
this.write_scalar(Scalar::from_i32(clock_id), &this.deref_pointer(clk_id_op)?)?;
Ok(Scalar::from_i32(0))
}
@ -691,7 +691,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// This might lead to false positives, see comment in pthread_mutexattr_destroy
this.write_uninit(
&this.deref_operand_as(attr_op, this.libc_ty_layout("pthread_condattr_t"))?,
&this.deref_pointer_as(attr_op, this.libc_ty_layout("pthread_condattr_t"))?,
)?;
Ok(0)
@ -784,7 +784,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// Extract the timeout.
let clock_id = cond_get_clock_id(this, cond_op)?;
let duration = match this
.read_timespec(&this.deref_operand_as(abstime_op, this.libc_ty_layout("timespec"))?)?
.read_timespec(&this.deref_pointer_as(abstime_op, this.libc_ty_layout("timespec"))?)?
{
Some(duration) => duration,
None => {
@ -867,7 +867,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
cond_get_clock_id(this, cond_op)?;
// This might lead to false positives, see comment in pthread_mutexattr_destroy
this.write_uninit(&this.deref_operand_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?)?;
this.write_uninit(&this.deref_pointer_as(cond_op, this.libc_ty_layout("pthread_cond_t"))?)?;
// FIXME: delete interpreter state associated with this condvar.
Ok(0)

View File

@ -13,7 +13,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
let thread_info_place = this.deref_operand_as(thread, this.libc_ty_layout("pthread_t"))?;
let thread_info_place = this.deref_pointer_as(thread, this.libc_ty_layout("pthread_t"))?;
let start_routine = this.read_pointer(start_routine)?;

View File

@ -91,7 +91,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let n = this.read_scalar(n)?.to_u32()?;
let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer
let io_status_block = this
.deref_operand_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?;
.deref_pointer_as(io_status_block, this.windows_ty_layout("IO_STATUS_BLOCK"))?;
if byte_offset != 0 {
throw_unsup_format!(
@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let [system_info] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
let system_info =
this.deref_operand_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
this.deref_pointer_as(system_info, this.windows_ty_layout("SYSTEM_INFO"))?;
// Initialize with `0`.
this.write_bytes_ptr(
system_info.ptr,
@ -391,8 +391,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let [console, buffer_info] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.read_target_isize(console)?;
// FIXME: this should use deref_operand_as, but CONSOLE_SCREEN_BUFFER_INFO is not in std
this.deref_operand(buffer_info)?;
// FIXME: this should use deref_pointer_as, but CONSOLE_SCREEN_BUFFER_INFO is not in std
this.deref_pointer(buffer_info)?;
// Indicate an error.
// FIXME: we should set last_error, but to what?
this.write_null(dest)?;
@ -508,7 +508,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let [console, mode] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.read_target_isize(console)?;
this.deref_operand(mode)?;
this.deref_pointer(mode)?;
// Indicate an error.
this.write_null(dest)?;
}

View File

@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let id = this.init_once_get_id(init_once_op)?;
let flags = this.read_scalar(flags_op)?.to_u32()?;
let pending_place = this.deref_operand(pending_op)?.into();
let pending_place = this.deref_pointer(pending_op)?.into();
let context = this.read_pointer(context_op)?;
if flags != 0 {

View File

@ -29,7 +29,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
let thread = if this.ptr_is_null(this.read_pointer(thread_op)?)? {
None
} else {
let thread_info_place = this.deref_operand(thread_op)?;
let thread_info_place = this.deref_pointer(thread_op)?;
Some(thread_info_place)
};

View File

@ -1,6 +1,6 @@
use std::alloc::{alloc, dealloc, Layout};
//@error-in-other-file: dereferenced after this allocation got freed
//@error-in-other-file: has been freed
fn main() {
unsafe {

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
--> RUSTLIB/alloc/src/alloc.rs:LL:CC
|
LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling
|
= 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,6 +4,6 @@ fn main() {
unsafe {
let x = alloc(Layout::from_size_align_unchecked(1, 1));
let _y = realloc(x, Layout::from_size_align_unchecked(1, 1), 1);
let _z = *x; //~ ERROR: dereferenced after this allocation got freed
let _z = *x; //~ ERROR: has been freed
}
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/reallocate-change-alloc.rs:LL:CC
|
LL | let _z = *x;
| ^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
|
= 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,6 +1,6 @@
use std::alloc::{alloc, dealloc, realloc, Layout};
//@error-in-other-file: dereferenced after this allocation got freed
//@error-in-other-file: has been freed
fn main() {
unsafe {

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
--> RUSTLIB/alloc/src/alloc.rs:LL:CC
|
LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling
|
= 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

@ -11,6 +11,6 @@ unsafe impl Send for SendRaw {}
fn main() {
unsafe {
let dangling_ptr = std::thread::spawn(|| SendRaw(&TLS as *const u8)).join().unwrap();
let _val = *dangling_ptr.0; //~ ERROR: dereferenced after this allocation got freed
let _val = *dangling_ptr.0; //~ ERROR: has been freed
}
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/thread_local_static_dealloc.rs:LL:CC
|
LL | let _val = *dangling_ptr.0;
| ^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
|
= 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

@ -7,6 +7,6 @@ fn main() {
let b = Box::new(42);
&*b as *const i32
};
let x = unsafe { ptr::addr_of!(*p) }; //~ ERROR: dereferenced after this allocation got freed
let x = unsafe { ptr::addr_of!(*p) }; //~ ERROR: has been freed
panic!("this should never print: {:?}", x);
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/dangling_pointer_addr_of.rs:LL:CC
|
LL | let x = unsafe { ptr::addr_of!(*p) };
| ^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
|
= 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,6 +6,6 @@ fn main() {
let b = Box::new(42);
&*b as *const i32
};
let x = unsafe { *p }; //~ ERROR: dereferenced after this allocation got freed
let x = unsafe { *p }; //~ ERROR: has been freed
panic!("this should never print: {}", x);
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/dangling_pointer_deref.rs:LL:CC
|
LL | let x = unsafe { *p };
| ^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
|
= 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

@ -0,0 +1,11 @@
// Make sure we find these even with many checks disabled.
//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation
fn main() {
let p = {
let b = Box::new(42);
&*b as *const i32
};
let x = unsafe { p.offset(42) }; //~ ERROR: /out-of-bounds pointer arithmetic: .* has been freed/
panic!("this should never print: {:?}", x);
}

View File

@ -0,0 +1,15 @@
error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling
--> $DIR/dangling_pointer_offset.rs:LL:CC
|
LL | let x = unsafe { p.offset(42) };
| ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling
|
= 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
= note: BACKTRACE:
= note: inside `main` at $DIR/dangling_pointer_offset.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
error: aborting due to previous error

View File

@ -7,7 +7,7 @@ fn main() {
&*b as *const i32
};
unsafe {
let _ = *p; //~ ERROR: dereferenced after this allocation got freed
let _ = *p; //~ ERROR: has been freed
}
panic!("this should never print");
}

View File

@ -1,13 +1,13 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
--> $DIR/dangling_pointer_deref_underscore.rs:LL:CC
error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/dangling_pointer_project_underscore.rs:LL:CC
|
LL | let _ = *p;
| ^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
|
= 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
= note: BACKTRACE:
= note: inside `main` at $DIR/dangling_pointer_deref_underscore.rs:LL:CC
= note: inside `main` at $DIR/dangling_pointer_project_underscore.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

View File

@ -6,5 +6,5 @@ fn main() {
let b = Box::new(42);
&*b as *const i32 as *const ()
};
let _x = unsafe { *p }; //~ ERROR: dereferenced after this allocation got freed
let _x = unsafe { *p }; //~ ERROR: has been freed
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/dangling_zst_deref.rs:LL:CC
|
LL | let _x = unsafe { *p };
| ^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
|
= 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

@ -8,7 +8,7 @@ unsafe fn make_ref<'a>(x: *mut i32) -> &'a mut i32 {
fn main() {
unsafe {
let x = make_ref(&mut 0); // The temporary storing "0" is deallocated at the ";"!
let val = *x; //~ ERROR: dereferenced after this allocation got freed
let val = *x; //~ ERROR: has been freed
println!("{}", val);
}
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/stack_temporary.rs:LL:CC
|
LL | let val = *x;
| ^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
|
= 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

@ -32,7 +32,7 @@ pub fn main() {
let ptr = ptr; // avoid field capturing
// Also an error of the form: Data race detected between (1) Deallocate on thread `<unnamed>` and (2) Read on thread `<unnamed>`
// but the invalid allocation is detected first.
*ptr.0 //~ ERROR: dereferenced after this allocation got freed
*ptr.0 //~ ERROR: has been freed
});
j1.join().unwrap();

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/dealloc_read_race2.rs:LL:CC
|
LL | *ptr.0
| ^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
|
= 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

@ -31,7 +31,7 @@ pub fn main() {
let ptr = ptr; // avoid field capturing
// Also an error of the form: Data race detected between (1) Deallocate on thread `<unnamed>` and (2) Write on thread `<unnamed>`
// but the invalid allocation is detected first.
*ptr.0 = 2; //~ ERROR: dereferenced after this allocation got freed
*ptr.0 = 2; //~ ERROR: has been freed
});
j1.join().unwrap();

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/dealloc_write_race2.rs:LL:CC
|
LL | *ptr.0 = 2;
| ^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
|
= 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

@ -20,5 +20,5 @@ fn main() {
let pointer = get_environ();
let _x = unsafe { *pointer };
std::env::set_var("FOO", "BAR");
let _y = unsafe { *pointer }; //~ ERROR: dereferenced after this allocation got freed
let _y = unsafe { *pointer }; //~ ERROR: has been freed
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/environ-gets-deallocated.rs:LL:CC
|
LL | let _y = unsafe { *pointer };
| ^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
|
= 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

@ -13,7 +13,7 @@ fn firstn() -> impl Generator<Yield = u64, Return = ()> {
*num += 0;
yield *num;
*num += 1; //~ERROR: dereferenced after this allocation got freed
*num += 1; //~ERROR: has been freed
}
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/generator-pinned-moved.rs:LL:CC
|
LL | *num += 1;
| ^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
|
= 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

@ -16,5 +16,5 @@ fn main() {
drop(strong);
// But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to
// undefined behaviour.
assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); //~ ERROR: dereferenced after this allocation got freed
assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); //~ ERROR: has been freed
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/rc_as_ptr.rs:LL:CC
|
LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
|
= 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

@ -14,6 +14,6 @@ fn main() {
0,
);
libc::munmap(ptr, 4096);
let _x = *(ptr as *mut u8); //~ ERROR: was dereferenced after this allocation got freed
let _x = *(ptr as *mut u8); //~ ERROR: has been freed
}
}

View File

@ -13,11 +13,11 @@ LL | libc::munmap(ptr, 4096);
= note: BACKTRACE:
= note: inside `main` at $DIR/mmap_use_after_munmap.rs:LL:CC
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/mmap_use_after_munmap.rs:LL:CC
|
LL | let _x = *(ptr as *mut u8);
| ^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
|
= 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

@ -8,5 +8,5 @@ fn main() {
let mut x_box = Box::new(1u8);
let x = &mut *x_box as *mut _ as *mut [u8; 0];
drop(x_box);
unsafe { *x = zst_val }; //~ ERROR: dereferenced after this allocation got freed
unsafe { *x = zst_val }; //~ ERROR: has been freed
}

View File

@ -1,8 +1,8 @@
error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed
error: Undefined Behavior: dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
--> $DIR/zst2.rs:LL:CC
|
LL | unsafe { *x = zst_val };
| ^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed
| ^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has been freed, so this pointer is dangling
|
= 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,13 +2,13 @@ error[E0080]: evaluation of constant value failed
--> $DIR/dealloc_intrinsic_dangling.rs:10:5
|
LL | &*ptr
| ^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
| ^^^^^ dereferencing pointer failed: alloc2 has been freed, so this pointer is dangling
error[E0080]: evaluation of constant value failed
--> $DIR/dealloc_intrinsic_dangling.rs:18:5
|
LL | *reference
| ^^^^^^^^^^ pointer to alloc4 was dereferenced after this allocation got freed
| ^^^^^^^^^^ dereferencing pointer failed: alloc4 has been freed, so this pointer is dangling
error: aborting due to 2 previous errors

View File

@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
--> $DIR/dealloc_intrinsic_duplicate.rs:9:5
|
LL | intrinsics::const_deallocate(ptr, 4, 4);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: alloc2 has been freed, so this pointer is dangling
error: aborting due to previous error

View File

@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
--> $DIR/issue-49296.rs:9:16
|
LL | const X: u64 = *wat(42);
| ^^^^^^^^ pointer to alloc3 was dereferenced after this allocation got freed
| ^^^^^^^^ dereferencing pointer failed: alloc3 has been freed, so this pointer is dangling
error: aborting due to previous error