1
Fork 0

make use of symbolic vtables in interpreter

This commit is contained in:
Ralf Jung 2022-07-17 16:02:49 -04:00
parent a10d8e4581
commit fe00573324
23 changed files with 282 additions and 376 deletions

View file

@ -299,29 +299,35 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} }
(&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
let val = self.read_immediate(src)?; let val = self.read_immediate(src)?;
let (old_data, old_vptr) = val.to_scalar_pair()?;
let old_vptr = self.scalar_to_ptr(old_vptr)?;
if data_a.principal_def_id() == data_b.principal_def_id() { if data_a.principal_def_id() == data_b.principal_def_id() {
return self.write_immediate(*val, dest); return self.write_immediate(*val, dest);
} }
// trait upcasting coercion // trait upcasting coercion
let vptr_entry_idx = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot(( let Some(vptr_entry_idx) = self.tcx.vtable_trait_upcasting_coercion_new_vptr_slot((
src_pointee_ty, src_pointee_ty,
dest_pointee_ty, dest_pointee_ty,
)); )) else {
return self.write_immediate(*val, dest);
};
if let Some(entry_idx) = vptr_entry_idx { let (ty, _) = self.get_ptr_vtable(old_vptr)?;
let entry_idx = u64::try_from(entry_idx).unwrap(); let Some(ty::VtblEntry::TraitVPtr(new_trait)) = self.get_vtable_entries(old_vptr)?.get(vptr_entry_idx) else {
let (old_data, old_vptr) = val.to_scalar_pair()?; throw_ub_format!(
let old_vptr = self.scalar_to_ptr(old_vptr)?; "upcasting to index {vptr_entry_idx} of vtable {old_vptr} but \
let new_vptr = self that vtable is too small or does not have an upcast-vtable at that index"
.read_new_vtable_after_trait_upcasting_from_vtable(old_vptr, entry_idx)?; )
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest) };
} else { let new_trait = new_trait.map_bound(|trait_ref| {
self.write_immediate(*val, dest) ty::ExistentialTraitRef::erase_self_ty(*self.tcx, trait_ref)
} });
let new_vptr = self.get_vtable_ptr(ty, Some(new_trait))?;
self.write_immediate(Immediate::new_dyn_trait(old_data, new_vptr, self), dest)
} }
(_, &ty::Dynamic(ref data, _)) => { (_, &ty::Dynamic(ref data, _)) => {
// Initial cast from sized to dyn trait // Initial cast from sized to dyn trait
let vtable = self.get_vtable(src_pointee_ty, data.principal())?; let vtable = self.get_vtable_ptr(src_pointee_ty, data.principal())?;
let ptr = self.read_immediate(src)?.to_scalar()?; let ptr = self.read_immediate(src)?.to_scalar()?;
let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx); let val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx);
self.write_immediate(val, dest) self.write_immediate(val, dest)

View file

@ -631,7 +631,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ty::Dynamic(..) => { ty::Dynamic(..) => {
let vtable = self.scalar_to_ptr(metadata.unwrap_meta())?; let vtable = self.scalar_to_ptr(metadata.unwrap_meta())?;
// Read size and align from vtable (already checks size). // Read size and align from vtable (already checks size).
Ok(Some(self.read_size_and_align_from_vtable(vtable)?)) Ok(Some(self.get_vtable_size_and_align(vtable)?))
} }
ty::Slice(_) | ty::Str => { ty::Slice(_) | ty::Str => {

View file

@ -16,7 +16,7 @@ use std::ptr;
use rustc_ast::Mutability; use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_middle::mir::display_allocation; use rustc_middle::mir::display_allocation;
use rustc_middle::ty::{Instance, ParamEnv, TyCtxt}; use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
use rustc_target::abi::{Align, HasDataLayout, Size}; use rustc_target::abi::{Align, HasDataLayout, Size};
use super::{ use super::{
@ -500,6 +500,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// contains a reference to memory that was created during its evaluation (i.e., not // contains a reference to memory that was created during its evaluation (i.e., not
// to another static), those inner references only exist in "resolved" form. // to another static), those inner references only exist in "resolved" form.
if self.tcx.is_foreign_item(def_id) { if self.tcx.is_foreign_item(def_id) {
// This is unreachable in Miri, but can happen in CTFE where we actually *do* support
// referencing arbitrary (declared) extern statics.
throw_unsup!(ReadExternStatic(def_id)); throw_unsup!(ReadExternStatic(def_id));
} }
@ -670,11 +672,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Can't do this in the match argument, we may get cycle errors since the lock would // Can't do this in the match argument, we may get cycle errors since the lock would
// be held throughout the match. // be held throughout the match.
match self.tcx.try_get_global_alloc(id) { match self.tcx.try_get_global_alloc(id) {
Some(GlobalAlloc::Static(did)) => { Some(GlobalAlloc::Static(def_id)) => {
assert!(!self.tcx.is_thread_local_static(did)); assert!(self.tcx.is_static(def_id));
assert!(!self.tcx.is_thread_local_static(def_id));
// Use size and align of the type. // Use size and align of the type.
let ty = self.tcx.type_of(did); let ty = self.tcx.type_of(def_id);
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
assert!(!layout.is_unsized());
(layout.size, layout.align.abi, AllocKind::LiveData) (layout.size, layout.align.abi, AllocKind::LiveData)
} }
Some(GlobalAlloc::Memory(alloc)) => { Some(GlobalAlloc::Memory(alloc)) => {
@ -685,8 +689,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} }
Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"), Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"),
Some(GlobalAlloc::Vtable(..)) => { Some(GlobalAlloc::Vtable(..)) => {
// No data to be accessed here. // No data to be accessed here. But vtables are pointer-aligned.
return (Size::ZERO, Align::ONE, AllocKind::Vtable); return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::Vtable);
} }
// The rest must be dead. // The rest must be dead.
None => { None => {
@ -726,7 +730,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
&self, &self,
ptr: Pointer<Option<M::Provenance>>, ptr: Pointer<Option<M::Provenance>>,
) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
trace!("get_fn({:?})", ptr); trace!("get_ptr_fn({:?})", ptr);
let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr)?; let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr)?;
if offset.bytes() != 0 { if offset.bytes() != 0 {
throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))) throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset)))
@ -735,6 +739,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
.ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into()) .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into())
} }
pub fn get_ptr_vtable(
&self,
ptr: Pointer<Option<M::Provenance>>,
) -> InterpResult<'tcx, (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>)> {
trace!("get_ptr_vtable({:?})", ptr);
let (alloc_id, offset, _tag) = self.ptr_get_alloc_id(ptr)?;
if offset.bytes() != 0 {
throw_ub!(InvalidVtablePointer(Pointer::new(alloc_id, offset)))
}
match self.tcx.try_get_global_alloc(alloc_id) {
Some(GlobalAlloc::Vtable(ty, trait_ref)) => Ok((ty, trait_ref)),
_ => throw_ub!(InvalidVtablePointer(Pointer::new(alloc_id, offset))),
}
}
pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> { pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> {
self.get_alloc_raw_mut(id)?.0.mutability = Mutability::Not; self.get_alloc_raw_mut(id)?.0.mutability = Mutability::Not;
Ok(()) Ok(())

View file

@ -885,28 +885,19 @@ where
} }
/// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
/// Also return some more information so drop doesn't have to run the same code twice.
pub(super) fn unpack_dyn_trait( pub(super) fn unpack_dyn_trait(
&self, &self,
mplace: &MPlaceTy<'tcx, M::Provenance>, mplace: &MPlaceTy<'tcx, M::Provenance>,
) -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::Provenance>)> { ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
let vtable = self.scalar_to_ptr(mplace.vtable())?; // also sanity checks the type let vtable = self.scalar_to_ptr(mplace.vtable())?; // also sanity checks the type
let (instance, ty) = self.read_drop_type_from_vtable(vtable)?; let (ty, _) = self.get_ptr_vtable(vtable)?;
let layout = self.layout_of(ty)?; let layout = self.layout_of(ty)?;
// More sanity checks
if cfg!(debug_assertions) {
let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
assert_eq!(size, layout.size);
// only ABI alignment is preserved
assert_eq!(align, layout.align.abi);
}
let mplace = MPlaceTy { let mplace = MPlaceTy {
mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace },
layout, layout,
align: layout.align.abi, align: layout.align.abi,
}; };
Ok((instance, mplace)) Ok(mplace)
} }
} }

View file

@ -1,5 +1,4 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::convert::TryFrom;
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
use rustc_middle::ty::Instance; use rustc_middle::ty::Instance;
@ -563,7 +562,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ty::Dynamic(..) ty::Dynamic(..)
)); ));
let vtable = self.scalar_to_ptr(receiver_place.meta.unwrap_meta())?; let vtable = self.scalar_to_ptr(receiver_place.meta.unwrap_meta())?;
let fn_val = self.get_vtable_slot(vtable, u64::try_from(idx).unwrap())?; let Some(ty::VtblEntry::Method(fn_inst)) = self.get_vtable_entries(vtable)?.get(idx).copied() else {
throw_ub_format!(
"calling index {idx} of vtable {vtable} but \
that vtable is too small or does not have a method at that index"
)
};
// `*mut receiver_place.layout.ty` is almost the layout that we // `*mut receiver_place.layout.ty` is almost the layout that we
// want for args[0]: We have to project to field 0 because we want // want for args[0]: We have to project to field 0 because we want
@ -579,7 +583,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
trace!("Patched receiver operand to {:#?}", args[0]); trace!("Patched receiver operand to {:#?}", args[0]);
// recurse with concrete function // recurse with concrete function
self.eval_fn_call( self.eval_fn_call(
fn_val, FnVal::Instance(fn_inst),
(caller_abi, caller_fn_abi), (caller_abi, caller_fn_abi),
&args, &args,
with_caller_location, with_caller_location,
@ -606,8 +610,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let (instance, place) = match place.layout.ty.kind() { let (instance, place) = match place.layout.ty.kind() {
ty::Dynamic(..) => { ty::Dynamic(..) => {
// Dropping a trait object. // Dropping a trait object. Need to find actual drop fn.
self.unpack_dyn_trait(&place)? let place = self.unpack_dyn_trait(&place)?;
let instance = ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
(instance, place)
} }
_ => (instance, place), _ => (instance, place),
}; };

View file

@ -1,14 +1,10 @@
use std::convert::TryFrom; use rustc_middle::mir::interpret::{InterpResult, Pointer};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::mir::interpret::{alloc_range, InterpResult, Pointer, PointerArithmetic}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{
self, Ty, TyCtxt, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE,
COMMON_VTABLE_ENTRIES_SIZE,
};
use rustc_target::abi::{Align, Size}; use rustc_target::abi::{Align, Size};
use super::util::ensure_monomorphic_enough; use super::util::ensure_monomorphic_enough;
use super::{FnVal, InterpCx, Machine}; use super::{InterpCx, Machine};
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// Creates a dynamic vtable for the given type and vtable origin. This is used only for /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
@ -17,8 +13,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
/// The `trait_ref` encodes the erased self type. Hence, if we are /// The `trait_ref` encodes the erased self type. Hence, if we are
/// making an object `Foo<Trait>` from a value of type `Foo<T>`, then /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
/// `trait_ref` would map `T: Trait`. /// `trait_ref` would map `T: Trait`.
pub fn get_vtable( pub fn get_vtable_ptr(
&mut self, &self,
ty: Ty<'tcx>, ty: Ty<'tcx>,
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>, poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> { ) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
@ -30,114 +26,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ensure_monomorphic_enough(*self.tcx, ty)?; ensure_monomorphic_enough(*self.tcx, ty)?;
ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?; ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?;
let vtable_allocation = self.tcx.vtable_allocation((ty, poly_trait_ref)); let vtable_symbolic_allocation = self.tcx.create_vtable_alloc(ty, poly_trait_ref);
let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_symbolic_allocation))?;
let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_allocation))?;
Ok(vtable_ptr.into()) Ok(vtable_ptr.into())
} }
/// Resolves the function at the specified slot in the provided /// Returns a high-level representation of the entires of the given vtable.
/// vtable. Currently an index of '3' (`TyCtxt::COMMON_VTABLE_ENTRIES.len()`) pub fn get_vtable_entries(
/// corresponds to the first method declared in the trait of the provided vtable.
pub fn get_vtable_slot(
&self, &self,
vtable: Pointer<Option<M::Provenance>>, vtable: Pointer<Option<M::Provenance>>,
idx: u64, ) -> InterpResult<'tcx, &'tcx [ty::VtblEntry<'tcx>]> {
) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { let (ty, poly_trait_ref) = self.get_ptr_vtable(vtable)?;
let ptr_size = self.pointer_size(); Ok(if let Some(poly_trait_ref) = poly_trait_ref {
let vtable_slot = vtable.offset(ptr_size * idx, self)?; let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
let vtable_slot = self let trait_ref = self.tcx.erase_regions(trait_ref);
.get_ptr_alloc(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)? self.tcx.vtable_entries(trait_ref)
.expect("cannot be a ZST"); } else {
let fn_ptr = self.scalar_to_ptr(vtable_slot.read_pointer(Size::ZERO)?.check_init()?)?; TyCtxt::COMMON_VTABLE_ENTRIES
self.get_ptr_fn(fn_ptr) })
} }
/// Returns the drop fn instance as well as the actual dynamic type. pub fn get_vtable_size_and_align(
pub fn read_drop_type_from_vtable(
&self,
vtable: Pointer<Option<M::Provenance>>,
) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> {
let pointer_size = self.pointer_size();
// We don't care about the pointee type; we just want a pointer.
let vtable = self
.get_ptr_alloc(
vtable,
pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(),
self.tcx.data_layout.pointer_align.abi,
)?
.expect("cannot be a ZST");
let drop_fn = vtable
.read_pointer(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE).unwrap())?
.check_init()?;
// We *need* an instance here, no other kind of function value, to be able
// to determine the type.
let drop_instance = self.get_ptr_fn(self.scalar_to_ptr(drop_fn)?)?.as_instance()?;
trace!("Found drop fn: {:?}", drop_instance);
let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx);
let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig);
// The drop function takes `*mut T` where `T` is the type being dropped, so get that.
let args = fn_sig.inputs();
if args.len() != 1 {
throw_ub!(InvalidVtableDropFn(fn_sig));
}
let ty =
args[0].builtin_deref(true).ok_or_else(|| err_ub!(InvalidVtableDropFn(fn_sig)))?.ty;
Ok((drop_instance, ty))
}
pub fn read_size_and_align_from_vtable(
&self, &self,
vtable: Pointer<Option<M::Provenance>>, vtable: Pointer<Option<M::Provenance>>,
) -> InterpResult<'tcx, (Size, Align)> { ) -> InterpResult<'tcx, (Size, Align)> {
let pointer_size = self.pointer_size(); let (ty, _trait_ref) = self.get_ptr_vtable(vtable)?;
// We check for `size = 3 * ptr_size`, which covers the drop fn (unused here), let layout = self.layout_of(ty)?;
// the size, and the align (which we read below). assert!(!layout.is_unsized(), "there are no vtables for unsized types");
let vtable = self Ok((layout.size, layout.align.abi))
.get_ptr_alloc(
vtable,
pointer_size * u64::try_from(TyCtxt::COMMON_VTABLE_ENTRIES.len()).unwrap(),
self.tcx.data_layout.pointer_align.abi,
)?
.expect("cannot be a ZST");
let size = vtable
.read_integer(alloc_range(
pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap(),
pointer_size,
))?
.check_init()?;
let size = size.to_machine_usize(self)?;
let size = Size::from_bytes(size);
let align = vtable
.read_integer(alloc_range(
pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap(),
pointer_size,
))?
.check_init()?;
let align = align.to_machine_usize(self)?;
let align = Align::from_bytes(align).map_err(|e| err_ub!(InvalidVtableAlignment(e)))?;
if size > self.max_size_of_val() {
throw_ub!(InvalidVtableSize);
}
Ok((size, align))
}
pub fn read_new_vtable_after_trait_upcasting_from_vtable(
&self,
vtable: Pointer<Option<M::Provenance>>,
idx: u64,
) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
let pointer_size = self.pointer_size();
let vtable_slot = vtable.offset(pointer_size * idx, self)?;
let new_vtable = self
.get_ptr_alloc(vtable_slot, pointer_size, self.tcx.data_layout.pointer_align.abi)?
.expect("cannot be a ZST");
let new_vtable = self.scalar_to_ptr(new_vtable.read_pointer(Size::ZERO)?.check_init()?)?;
Ok(new_vtable)
} }
} }

View file

@ -313,50 +313,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
match tail.kind() { match tail.kind() {
ty::Dynamic(..) => { ty::Dynamic(..) => {
let vtable = self.ecx.scalar_to_ptr(meta.unwrap_meta())?; let vtable = self.ecx.scalar_to_ptr(meta.unwrap_meta())?;
// Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. // Make sure it is a genuine vtable pointer.
try_validation!( let (_ty, _trait) = try_validation!(
self.ecx.check_ptr_access_align( self.ecx.get_ptr_vtable(vtable),
vtable,
3 * self.ecx.tcx.data_layout.pointer_size, // drop, size, align
self.ecx.tcx.data_layout.pointer_align.abi,
CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
),
self.path, self.path,
err_ub!(DanglingIntPointer(..)) | err_ub!(DanglingIntPointer(..)) |
err_ub!(PointerUseAfterFree(..)) => err_ub!(InvalidVtablePointer(..)) =>
{ "dangling vtable pointer in wide pointer" }, { "{vtable}" } expected { "a vtable pointer" },
err_ub!(AlignmentCheckFailed { .. }) =>
{ "unaligned vtable pointer in wide pointer" },
err_ub!(PointerOutOfBounds { .. }) =>
{ "too small vtable" },
); );
try_validation!( // FIXME: check if the type/trait match what ty::Dynamic says?
self.ecx.read_drop_type_from_vtable(vtable),
self.path,
err_ub!(DanglingIntPointer(..)) |
err_ub!(InvalidFunctionPointer(..)) =>
{ "invalid drop function pointer in vtable (not pointing to a function)" },
err_ub!(InvalidVtableDropFn(..)) =>
{ "invalid drop function pointer in vtable (function has incompatible signature)" },
// Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123.
// (We assume there are no other MachineStop errors possible here.)
InterpError::MachineStop(_) =>
{ "vtable pointer does not have permission to read drop function pointer" },
);
try_validation!(
self.ecx.read_size_and_align_from_vtable(vtable),
self.path,
err_ub!(InvalidVtableSize) =>
{ "invalid vtable: size is bigger than largest supported object" },
err_ub!(InvalidVtableAlignment(msg)) =>
{ "invalid vtable: alignment {}", msg },
err_unsup!(ReadPointerAsBytes) => { "invalid size or align in vtable" },
// Stacked Borrows errors can happen here, see https://github.com/rust-lang/miri/issues/2123.
// (We assume there are no other MachineStop errors possible here.)
InterpError::MachineStop(_) =>
{ "vtable pointer does not have permission to read size and alignment" },
);
// FIXME: More checks for the vtable.
} }
ty::Slice(..) | ty::Str => { ty::Slice(..) | ty::Str => {
let _len = try_validation!( let _len = try_validation!(
@ -607,11 +572,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
let _fn = try_validation!( let _fn = try_validation!(
self.ecx.get_ptr_fn(ptr), self.ecx.get_ptr_fn(ptr),
self.path, self.path,
err_ub!(DanglingIntPointer(0, _)) =>
{ "a null function pointer" },
err_ub!(DanglingIntPointer(..)) | err_ub!(DanglingIntPointer(..)) |
err_ub!(InvalidFunctionPointer(..)) => err_ub!(InvalidFunctionPointer(..)) =>
{ "{:x}", value } expected { "a function pointer" }, { "{ptr}" } expected { "a function pointer" },
); );
// FIXME: Check if the signature matches // FIXME: Check if the signature matches
} else { } else {

View file

@ -425,7 +425,7 @@ macro_rules! make_value_visitor {
// unsized values are never immediate, so we can assert_mem_place // unsized values are never immediate, so we can assert_mem_place
let op = v.to_op_for_read(self.ecx())?; let op = v.to_op_for_read(self.ecx())?;
let dest = op.assert_mem_place(); let dest = op.assert_mem_place();
let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?.1; let inner_mplace = self.ecx().unpack_dyn_trait(&dest)?;
trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout); trace!("walk_value: dyn object layout: {:#?}", inner_mplace.layout);
// recurse with the inner type // recurse with the inner type
return self.visit_field(&v, 0, &$value_trait::from_op(&inner_mplace.into())); return self.visit_field(&v, 0, &$value_trait::from_op(&inner_mplace.into()));

View file

@ -1,7 +1,7 @@
use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar}; use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
use crate::mir::interpret::ConstValue; use crate::mir::interpret::ConstValue;
use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree}; use crate::ty::{layout, query::TyCtxtAt, tls, Ty, ValTree};
use rustc_data_structures::sync::Lock; use rustc_data_structures::sync::Lock;
use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed}; use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed};
@ -219,7 +219,7 @@ pub struct ScalarSizeMismatch {
} }
/// Error information for when the program caused Undefined Behavior. /// Error information for when the program caused Undefined Behavior.
pub enum UndefinedBehaviorInfo<'tcx> { pub enum UndefinedBehaviorInfo {
/// Free-form case. Only for errors that are never caught! /// Free-form case. Only for errors that are never caught!
Ub(String), Ub(String),
/// Unreachable code was executed. /// Unreachable code was executed.
@ -241,12 +241,6 @@ pub enum UndefinedBehaviorInfo<'tcx> {
PointerArithOverflow, PointerArithOverflow,
/// Invalid metadata in a wide pointer (using `str` to avoid allocations). /// Invalid metadata in a wide pointer (using `str` to avoid allocations).
InvalidMeta(&'static str), InvalidMeta(&'static str),
/// Invalid drop function in vtable.
InvalidVtableDropFn(FnSig<'tcx>),
/// Invalid size in a vtable: too large.
InvalidVtableSize,
/// Invalid alignment in a vtable: too large, or not a power of 2.
InvalidVtableAlignment(String),
/// Reading a C string that does not end within its allocation. /// Reading a C string that does not end within its allocation.
UnterminatedCString(Pointer), UnterminatedCString(Pointer),
/// Dereferencing a dangling pointer after it got freed. /// Dereferencing a dangling pointer after it got freed.
@ -290,6 +284,8 @@ pub enum UndefinedBehaviorInfo<'tcx> {
InvalidTag(Scalar), InvalidTag(Scalar),
/// Using a pointer-not-to-a-function as function pointer. /// Using a pointer-not-to-a-function as function pointer.
InvalidFunctionPointer(Pointer), InvalidFunctionPointer(Pointer),
/// Using a pointer-not-to-a-vtable as vtable pointer.
InvalidVtablePointer(Pointer),
/// Using a string that is not valid UTF-8, /// Using a string that is not valid UTF-8,
InvalidStr(std::str::Utf8Error), InvalidStr(std::str::Utf8Error),
/// Using uninitialized data where it is not allowed. /// Using uninitialized data where it is not allowed.
@ -302,7 +298,7 @@ pub enum UndefinedBehaviorInfo<'tcx> {
UninhabitedEnumVariantWritten, UninhabitedEnumVariantWritten,
} }
impl fmt::Display for UndefinedBehaviorInfo<'_> { impl fmt::Display for UndefinedBehaviorInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use UndefinedBehaviorInfo::*; use UndefinedBehaviorInfo::*;
match self { match self {
@ -317,14 +313,6 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"), RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"),
PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"), PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {msg}"), InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {msg}"),
InvalidVtableDropFn(sig) => write!(
f,
"invalid drop function signature: got {sig}, expected exactly one argument which must be a pointer type",
),
InvalidVtableSize => {
write!(f, "invalid vtable: size is bigger than largest supported object")
}
InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {msg}"),
UnterminatedCString(p) => write!( UnterminatedCString(p) => write!(
f, f,
"reading a null-terminated string starting at {p:?} with no null found before end of allocation", "reading a null-terminated string starting at {p:?} with no null found before end of allocation",
@ -378,6 +366,9 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
InvalidFunctionPointer(p) => { InvalidFunctionPointer(p) => {
write!(f, "using {p:?} as function pointer but it does not point to a function") write!(f, "using {p:?} as function pointer but it does not point to a function")
} }
InvalidVtablePointer(p) => {
write!(f, "using {p:?} as vtable pointer but it does not point to a vtable")
}
InvalidStr(err) => write!(f, "this string is not valid UTF-8: {err}"), InvalidStr(err) => write!(f, "this string is not valid UTF-8: {err}"),
InvalidUninitBytes(Some((alloc, info))) => write!( InvalidUninitBytes(Some((alloc, info))) => write!(
f, f,
@ -497,7 +488,7 @@ impl dyn MachineStopType {
pub enum InterpError<'tcx> { pub enum InterpError<'tcx> {
/// The program caused undefined behavior. /// The program caused undefined behavior.
UndefinedBehavior(UndefinedBehaviorInfo<'tcx>), UndefinedBehavior(UndefinedBehaviorInfo),
/// The program did something the interpreter does not support (some of these *might* be UB /// The program did something the interpreter does not support (some of these *might* be UB
/// but the interpreter is not sure). /// but the interpreter is not sure).
Unsupported(UnsupportedOpInfo), Unsupported(UnsupportedOpInfo),

View file

@ -1,54 +0,0 @@
// run-pass
#![allow(dead_code)]
#[repr(C)]
union Transmute<T: Copy, U: Copy> {
t: T,
u: U,
}
trait Bar {
fn bar(&self) -> u32;
}
struct Foo {
foo: u32,
bar: bool,
}
impl Bar for Foo {
fn bar(&self) -> u32 {
self.foo
}
}
impl Drop for Foo {
fn drop(&mut self) {
assert!(!self.bar);
self.bar = true;
println!("dropping Foo");
}
}
#[derive(Copy, Clone)]
struct Fat<'a>(&'a Foo, &'static VTable);
struct VTable {
drop: Option<for<'a> fn(&'a mut Foo)>,
size: usize,
align: usize,
bar: for<'a> fn(&'a Foo) -> u32,
}
const FOO: &dyn Bar = &Foo { foo: 128, bar: false };
const G: Fat = unsafe { Transmute { t: FOO }.u };
const F: Option<for<'a> fn(&'a mut Foo)> = G.1.drop;
const H: for<'a> fn(&'a Foo) -> u32 = G.1.bar;
fn main() {
let mut foo = Foo { foo: 99, bar: false };
(F.unwrap())(&mut foo);
std::mem::forget(foo); // already ran the drop impl
assert_eq!(H(&Foo { foo: 42, bar: false }), 42);
}

View file

@ -2,19 +2,19 @@ error[E0080]: evaluation of constant value failed
--> $DIR/ub-incorrect-vtable.rs:19:14 --> $DIR/ub-incorrect-vtable.rs:19:14
| |
LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: alignment `1000` is not a power of 2 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: evaluation of constant value failed error[E0080]: evaluation of constant value failed
--> $DIR/ub-incorrect-vtable.rs:24:14 --> $DIR/ub-incorrect-vtable.rs:24:14
| |
LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: size is bigger than largest supported object | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:34:1 --> $DIR/ub-incorrect-vtable.rs:33:1
| |
LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: alignment `1000` is not a power of 2 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) { = note: the raw bytes of the constant (size: 8, align: 4) {
@ -22,16 +22,38 @@ LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
} }
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:39:1 --> $DIR/ub-incorrect-vtable.rs:38:1
| |
LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: size is bigger than largest supported object | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) { = note: the raw bytes of the constant (size: 8, align: 4) {
╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼ ╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼
} }
error: aborting due to 4 previous errors error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:44:1
|
LL | const INVALID_VTABLE_UB: W<&dyn Trait> =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:91:1
|
LL | const G: Wide = unsafe { Transmute { t: FOO }.u };
| ^^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
╾─allocN─╼ ╾─allocN─╼ │ ╾──╼╾──╼
}
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0080`. For more information about this error, try `rustc --explain E0080`.

View file

@ -2,19 +2,19 @@ error[E0080]: evaluation of constant value failed
--> $DIR/ub-incorrect-vtable.rs:19:14 --> $DIR/ub-incorrect-vtable.rs:19:14
| |
LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; LL | unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: alignment `1000` is not a power of 2 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: evaluation of constant value failed error[E0080]: evaluation of constant value failed
--> $DIR/ub-incorrect-vtable.rs:24:14 --> $DIR/ub-incorrect-vtable.rs:24:14
| |
LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; LL | unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid vtable: size is bigger than largest supported object | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:34:1 --> $DIR/ub-incorrect-vtable.rs:33:1
| |
LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: alignment `1000` is not a power of 2 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) { = note: the raw bytes of the constant (size: 16, align: 8) {
@ -22,16 +22,38 @@ LL | const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
} }
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:39:1 --> $DIR/ub-incorrect-vtable.rs:38:1
| |
LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = LL | const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid vtable: size is bigger than largest supported object | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) { = note: the raw bytes of the constant (size: 16, align: 8) {
╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼ ╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼
} }
error: aborting due to 4 previous errors error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:44:1
|
LL | const INVALID_VTABLE_UB: W<&dyn Trait> =
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-incorrect-vtable.rs:91:1
|
LL | const G: Wide = unsafe { Transmute { t: FOO }.u };
| ^^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation)
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
╾───────allocN───────╼ ╾───────allocN───────╼ │ ╾──────╼╾──────╼
}
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0080`. For more information about this error, try `rustc --explain E0080`.

View file

@ -18,27 +18,79 @@ trait Trait {}
const INVALID_VTABLE_ALIGNMENT: &dyn Trait = const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) }; unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
//~^ ERROR evaluation of constant value failed //~^ ERROR evaluation of constant value failed
//~| invalid vtable: alignment `1000` is not a power of 2 //~| does not point to a vtable
const INVALID_VTABLE_SIZE: &dyn Trait = const INVALID_VTABLE_SIZE: &dyn Trait =
unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) }; unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
//~^ ERROR evaluation of constant value failed //~^ ERROR evaluation of constant value failed
//~| invalid vtable: size is bigger than largest supported object //~| does not point to a vtable
#[repr(transparent)] #[repr(transparent)]
struct W<T>(T); struct W<T>(T);
// The drop fn is checked before size/align are, so get ourselves a "sufficiently valid" drop fn
fn drop_me(_: *mut usize) {} fn drop_me(_: *mut usize) {}
const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> = const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) }; unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) };
//~^^ ERROR it is undefined behavior to use this value //~^^ ERROR it is undefined behavior to use this value
//~| invalid vtable: alignment `1000` is not a power of 2 //~| expected a vtable pointer
const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> = const INVALID_VTABLE_SIZE_UB: W<&dyn Trait> =
unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) }; unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) };
//~^^ ERROR it is undefined behavior to use this value //~^^ ERROR it is undefined behavior to use this value
//~| invalid vtable: size is bigger than largest supported object //~| expected a vtable pointer
// Even if the vtable has a fn ptr and a reasonable size+align, it still does not work.
const INVALID_VTABLE_UB: W<&dyn Trait> =
unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1usize))) };
//~^^ ERROR it is undefined behavior to use this value
//~| expected a vtable pointer
// Trying to access the data in a vtable does not work, either.
#[derive(Copy, Clone)]
struct Wide<'a>(&'a Foo, &'static VTable);
struct VTable {
drop: Option<for<'a> fn(&'a mut Foo)>,
size: usize,
align: usize,
bar: for<'a> fn(&'a Foo) -> u32,
}
trait Bar {
fn bar(&self) -> u32;
}
struct Foo {
foo: u32,
bar: bool,
}
impl Bar for Foo {
fn bar(&self) -> u32 {
self.foo
}
}
impl Drop for Foo {
fn drop(&mut self) {
assert!(!self.bar);
self.bar = true;
println!("dropping Foo");
}
}
#[repr(C)]
union Transmute<T: Copy, U: Copy> {
t: T,
u: U,
}
const FOO: &dyn Bar = &Foo { foo: 128, bar: false };
const G: Wide = unsafe { Transmute { t: FOO }.u };
//~^ ERROR it is undefined behavior to use this value
//~| encountered a dangling reference
// (it is dangling because vtables do not contain memory that can be dereferenced)
fn main() {} fn main() {}

View file

@ -125,7 +125,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref-ptr.rs:56:1 --> $DIR/ub-ref-ptr.rs:56:1
| |
LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null function pointer | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) { = note: the raw bytes of the constant (size: 4, align: 4) {
@ -147,7 +147,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref-ptr.rs:60:1 --> $DIR/ub-ref-ptr.rs:60:1
| |
LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x0000000d, but expected a function pointer | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) { = note: the raw bytes of the constant (size: 4, align: 4) {
@ -158,7 +158,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref-ptr.rs:62:1 --> $DIR/ub-ref-ptr.rs:62:1
| |
LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered pointer to alloc41, but expected a function pointer | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) { = note: the raw bytes of the constant (size: 4, align: 4) {

View file

@ -125,7 +125,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref-ptr.rs:56:1 --> $DIR/ub-ref-ptr.rs:56:1
| |
LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null function pointer | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) { = note: the raw bytes of the constant (size: 8, align: 8) {
@ -147,7 +147,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref-ptr.rs:60:1 --> $DIR/ub-ref-ptr.rs:60:1
| |
LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x000000000000000d, but expected a function pointer | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) { = note: the raw bytes of the constant (size: 8, align: 8) {
@ -158,7 +158,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-ref-ptr.rs:62:1 --> $DIR/ub-ref-ptr.rs:62:1
| |
LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered pointer to alloc41, but expected a function pointer | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered alloc41, but expected a function pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) { = note: the raw bytes of the constant (size: 8, align: 8) {

View file

@ -6,7 +6,7 @@ LL | const BAD_UPVAR: &dyn FnOnce() = &{
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) { = note: the raw bytes of the constant (size: 8, align: 4) {
╾─alloc3──╼ ╾─alloc6──╼ │ ╾──╼╾──╼ ╾─alloc3──╼ ╾─alloc4──╼ │ ╾──╼╾──╼
} }
error: aborting due to previous error error: aborting due to previous error

View file

@ -6,7 +6,7 @@ LL | const BAD_UPVAR: &dyn FnOnce() = &{
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) { = note: the raw bytes of the constant (size: 16, align: 8) {
╾───────alloc3────────╼ ╾───────alloc6────────╼ │ ╾──────╼╾──────╼ ╾───────alloc3────────╼ ╾───────alloc4────────╼ │ ╾──────╼╾──────╼
} }
error: aborting due to previous error error: aborting due to previous error

View file

@ -209,7 +209,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:117:1 --> $DIR/ub-wide-ptr.rs:117:1
| |
LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) { = note: the raw bytes of the constant (size: 8, align: 4) {
@ -220,7 +220,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:120:1 --> $DIR/ub-wide-ptr.rs:120:1
| |
LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) { = note: the raw bytes of the constant (size: 8, align: 4) {
@ -231,51 +231,36 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:123:1 --> $DIR/ub-wide-ptr.rs:123:1
| |
LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered dangling vtable pointer in wide pointer | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) { = note: the raw bytes of the constant (size: 8, align: 4) {
╾allocN─╼ 04 00 00 00 │ ╾──╼.... ╾allocN─╼ 04 00 00 00 │ ╾──╼....
} }
error[E0080]: it is undefined behavior to use this value error[E0080]: evaluation of constant value failed
--> $DIR/ub-wide-ptr.rs:125:1 --> $DIR/ub-wide-ptr.rs:125:57
| |
LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered unaligned vtable pointer in wide pointer | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value error[E0080]: evaluation of constant value failed
--> $DIR/ub-wide-ptr.rs:127:1 --> $DIR/ub-wide-ptr.rs:128:57
| |
LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value error[E0080]: evaluation of constant value failed
--> $DIR/ub-wide-ptr.rs:129:1 --> $DIR/ub-wide-ptr.rs:131:56
| |
LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
╾allocN─╼ ╾allocN─╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:131:1 --> $DIR/ub-wide-ptr.rs:134:1
| |
LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid drop function pointer in vtable (not pointing to a function) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) { = note: the raw bytes of the constant (size: 8, align: 4) {
@ -283,7 +268,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans
} }
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:135:1 --> $DIR/ub-wide-ptr.rs:138:1
| |
LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
@ -294,10 +279,10 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_,
} }
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:139:1 --> $DIR/ub-wide-ptr.rs:142:1
| |
LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) { = note: the raw bytes of the constant (size: 8, align: 4) {
@ -305,10 +290,10 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute
} }
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:141:1 --> $DIR/ub-wide-ptr.rs:144:1
| |
LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered too small vtable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) { = note: the raw bytes of the constant (size: 8, align: 4) {
@ -316,16 +301,16 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm
} }
error[E0080]: could not evaluate static initializer error[E0080]: could not evaluate static initializer
--> $DIR/ub-wide-ptr.rs:147:5 --> $DIR/ub-wide-ptr.rs:150:5
| |
LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
error[E0080]: could not evaluate static initializer error[E0080]: could not evaluate static initializer
--> $DIR/ub-wide-ptr.rs:151:5 --> $DIR/ub-wide-ptr.rs:154:5
| |
LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: allocN has size N, so pointer to 12 bytes starting at offset N is out-of-bounds | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error: aborting due to 32 previous errors error: aborting due to 32 previous errors

View file

@ -209,7 +209,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:117:1 --> $DIR/ub-wide-ptr.rs:117:1
| |
LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) { = note: the raw bytes of the constant (size: 16, align: 8) {
@ -220,7 +220,7 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:120:1 --> $DIR/ub-wide-ptr.rs:120:1
| |
LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered too small vtable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) { = note: the raw bytes of the constant (size: 16, align: 8) {
@ -231,51 +231,36 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:123:1 --> $DIR/ub-wide-ptr.rs:123:1
| |
LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered dangling vtable pointer in wide pointer | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) { = note: the raw bytes of the constant (size: 16, align: 8) {
╾──────allocN───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ ╾──────allocN───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
} }
error[E0080]: it is undefined behavior to use this value error[E0080]: evaluation of constant value failed
--> $DIR/ub-wide-ptr.rs:125:1 --> $DIR/ub-wide-ptr.rs:125:57
| |
LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered unaligned vtable pointer in wide pointer | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value error[E0080]: evaluation of constant value failed
--> $DIR/ub-wide-ptr.rs:127:1 --> $DIR/ub-wide-ptr.rs:128:57
| |
LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value error[E0080]: evaluation of constant value failed
--> $DIR/ub-wide-ptr.rs:129:1 --> $DIR/ub-wide-ptr.rs:131:56
| |
LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (not pointing to a function) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) {
╾──────allocN───────╼ ╾──────allocN───────╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:131:1 --> $DIR/ub-wide-ptr.rs:134:1
| |
LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid drop function pointer in vtable (not pointing to a function) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered allocN, but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) { = note: the raw bytes of the constant (size: 16, align: 8) {
@ -283,7 +268,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans
} }
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:135:1 --> $DIR/ub-wide-ptr.rs:138:1
| |
LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
@ -294,10 +279,10 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_,
} }
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:139:1 --> $DIR/ub-wide-ptr.rs:142:1
| |
LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) { = note: the raw bytes of the constant (size: 16, align: 8) {
@ -305,10 +290,10 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute
} }
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:141:1 --> $DIR/ub-wide-ptr.rs:144:1
| |
LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered too small vtable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered allocN, but expected a vtable pointer
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) { = note: the raw bytes of the constant (size: 16, align: 8) {
@ -316,16 +301,16 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm
} }
error[E0080]: could not evaluate static initializer error[E0080]: could not evaluate static initializer
--> $DIR/ub-wide-ptr.rs:147:5 --> $DIR/ub-wide-ptr.rs:150:5
| |
LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance)
error[E0080]: could not evaluate static initializer error[E0080]: could not evaluate static initializer
--> $DIR/ub-wide-ptr.rs:151:5 --> $DIR/ub-wide-ptr.rs:154:5
| |
LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: allocN has size N, so pointer to 24 bytes starting at offset N is out-of-bounds | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
error: aborting due to 32 previous errors error: aborting due to 32 previous errors

View file

@ -123,11 +123,14 @@ const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8
const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
//~^ ERROR it is undefined behavior to use this value //~^ ERROR it is undefined behavior to use this value
const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) }; const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
//~^ ERROR it is undefined behavior to use this value //~^ ERROR evaluation of constant value failed
//~| does not point to a vtable
const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) }; const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
//~^ ERROR it is undefined behavior to use this value //~^ ERROR evaluation of constant value failed
//~| does not point to a vtable
const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) }; const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
//~^ ERROR it is undefined behavior to use this value //~^ ERROR evaluation of constant value failed
//~| does not point to a vtable
const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
//~^ ERROR it is undefined behavior to use this value //~^ ERROR it is undefined behavior to use this value

View file

@ -2,11 +2,11 @@ error[E0080]: it is undefined behavior to use this value
--> $DIR/issue-79690.rs:30:1 --> $DIR/issue-79690.rs:30:1
| |
LL | const G: Fat = unsafe { Transmute { t: FOO }.u }; LL | const G: Fat = unsafe { Transmute { t: FOO }.u };
| ^^^^^^^^^^^^ constructing invalid value at .1.<deref>.size.foo: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes | ^^^^^^^^^^^^ constructing invalid value at .1: encountered a dangling reference (going beyond the bounds of its allocation)
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) { = note: the raw bytes of the constant (size: 16, align: 8) {
╾───────alloc3────────╼ ╾───────alloc6────────╼ │ ╾──────╼╾──────╼ ╾───────alloc3────────╼ ╾───────alloc4────────╼ │ ╾──────╼╾──────╼
} }
error: aborting due to previous error error: aborting due to previous error

View file

@ -17,7 +17,7 @@ LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) { = note: the raw bytes of the constant (size: 8, align: 4) {
╾─alloc7──╼ ╾─alloc9──╼ │ ╾──╼╾──╼ ╾─alloc7──╼ ╾─alloc8──╼ │ ╾──╼╾──╼
} }
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
@ -28,7 +28,7 @@ LL | const BLUNT: &mut i32 = &mut 42;
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) { = note: the raw bytes of the constant (size: 4, align: 4) {
╾─alloc11─╼ │ ╾──╼ ╾─alloc10─╼ │ ╾──╼
} }
warning: skipping const checks warning: skipping const checks

View file

@ -17,7 +17,7 @@ LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) };
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 16, align: 8) { = note: the raw bytes of the constant (size: 16, align: 8) {
╾───────alloc7────────╼ ╾───────alloc9────────╼ │ ╾──────╼╾──────╼ ╾───────alloc7────────╼ ╾───────alloc8────────╼ │ ╾──────╼╾──────╼
} }
error[E0080]: it is undefined behavior to use this value error[E0080]: it is undefined behavior to use this value
@ -28,7 +28,7 @@ LL | const BLUNT: &mut i32 = &mut 42;
| |
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) { = note: the raw bytes of the constant (size: 8, align: 8) {
╾───────alloc11───────╼ │ ╾──────╼ ╾───────alloc10───────╼ │ ╾──────╼
} }
warning: skipping const checks warning: skipping const checks