}
(&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
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() {
return self.write_immediate(*val, dest);
}
// 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,
dest_pointee_ty,
- ));
-
- if let Some(entry_idx) = vptr_entry_idx {
- let entry_idx = u64::try_from(entry_idx).unwrap();
- let (old_data, old_vptr) = val.to_scalar_pair()?;
- let old_vptr = self.scalar_to_ptr(old_vptr)?;
- let new_vptr = self
- .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 {
- self.write_immediate(*val, dest)
- }
+ )) else {
+ return self.write_immediate(*val, dest);
+ };
+
+ let (ty, _) = self.get_ptr_vtable(old_vptr)?;
+ let Some(ty::VtblEntry::TraitVPtr(new_trait)) = self.get_vtable_entries(old_vptr)?.get(vptr_entry_idx) else {
+ throw_ub_format!(
+ "upcasting to index {vptr_entry_idx} of vtable {old_vptr} but \
+ that vtable is too small or does not have an upcast-vtable at that index"
+ )
+ };
+ let new_trait = new_trait.map_bound(|trait_ref| {
+ 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, _)) => {
// 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 val = Immediate::new_dyn_trait(ptr, vtable, &*self.tcx);
self.write_immediate(val, dest)
ty::Dynamic(..) => {
let vtable = self.scalar_to_ptr(metadata.unwrap_meta())?;
// 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 => {
use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
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 super::{
// 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.
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));
}
// Can't do this in the match argument, we may get cycle errors since the lock would
// be held throughout the match.
match self.tcx.try_get_global_alloc(id) {
- Some(GlobalAlloc::Static(did)) => {
- assert!(!self.tcx.is_thread_local_static(did));
+ Some(GlobalAlloc::Static(def_id)) => {
+ assert!(self.tcx.is_static(def_id));
+ assert!(!self.tcx.is_thread_local_static(def_id));
// 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();
+ assert!(!layout.is_unsized());
(layout.size, layout.align.abi, AllocKind::LiveData)
}
Some(GlobalAlloc::Memory(alloc)) => {
}
Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"),
Some(GlobalAlloc::Vtable(..)) => {
- // No data to be accessed here.
- return (Size::ZERO, Align::ONE, AllocKind::Vtable);
+ // No data to be accessed here. But vtables are pointer-aligned.
+ return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::Vtable);
}
// The rest must be dead.
None => {
&self,
ptr: Pointer<Option<M::Provenance>>,
) -> 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)?;
if offset.bytes() != 0 {
throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset)))
.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> {
self.get_alloc_raw_mut(id)?.0.mutability = Mutability::Not;
Ok(())
}
/// 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(
&self,
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 (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
+ let (ty, _) = self.get_ptr_vtable(vtable)?;
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 {
mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace },
layout,
align: layout.align.abi,
};
- Ok((instance, mplace))
+ Ok(mplace)
}
}
use std::borrow::Cow;
-use std::convert::TryFrom;
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
use rustc_middle::ty::Instance;
ty::Dynamic(..)
));
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
// want for args[0]: We have to project to field 0 because we want
trace!("Patched receiver operand to {:#?}", args[0]);
// recurse with concrete function
self.eval_fn_call(
- fn_val,
+ FnVal::Instance(fn_inst),
(caller_abi, caller_fn_abi),
&args,
with_caller_location,
let (instance, place) = match place.layout.ty.kind() {
ty::Dynamic(..) => {
- // Dropping a trait object.
- self.unpack_dyn_trait(&place)?
+ // Dropping a trait object. Need to find actual drop fn.
+ let place = self.unpack_dyn_trait(&place)?;
+ let instance = ty::Instance::resolve_drop_in_place(*self.tcx, place.layout.ty);
+ (instance, place)
}
_ => (instance, place),
};
-use std::convert::TryFrom;
-
-use rustc_middle::mir::interpret::{alloc_range, InterpResult, Pointer, PointerArithmetic};
-use rustc_middle::ty::{
- self, Ty, TyCtxt, COMMON_VTABLE_ENTRIES_ALIGN, COMMON_VTABLE_ENTRIES_DROPINPLACE,
- COMMON_VTABLE_ENTRIES_SIZE,
-};
+use rustc_middle::mir::interpret::{InterpResult, Pointer};
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_target::abi::{Align, Size};
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> {
/// Creates a dynamic vtable for the given type and vtable origin. This is used only for
/// 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
/// `trait_ref` would map `T: Trait`.
- pub fn get_vtable(
- &mut self,
+ pub fn get_vtable_ptr(
+ &self,
ty: Ty<'tcx>,
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
ensure_monomorphic_enough(*self.tcx, ty)?;
ensure_monomorphic_enough(*self.tcx, poly_trait_ref)?;
- let vtable_allocation = self.tcx.vtable_allocation((ty, poly_trait_ref));
-
- let vtable_ptr = self.global_base_pointer(Pointer::from(vtable_allocation))?;
-
+ 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))?;
Ok(vtable_ptr.into())
}
- /// Resolves the function at the specified slot in the provided
- /// vtable. Currently an index of '3' (`TyCtxt::COMMON_VTABLE_ENTRIES.len()`)
- /// corresponds to the first method declared in the trait of the provided vtable.
- pub fn get_vtable_slot(
+ /// Returns a high-level representation of the entires of the given vtable.
+ pub fn get_vtable_entries(
&self,
vtable: Pointer<Option<M::Provenance>>,
- idx: u64,
- ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
- let ptr_size = self.pointer_size();
- let vtable_slot = vtable.offset(ptr_size * idx, self)?;
- let vtable_slot = self
- .get_ptr_alloc(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)?
- .expect("cannot be a ZST");
- let fn_ptr = self.scalar_to_ptr(vtable_slot.read_pointer(Size::ZERO)?.check_init()?)?;
- self.get_ptr_fn(fn_ptr)
+ ) -> InterpResult<'tcx, &'tcx [ty::VtblEntry<'tcx>]> {
+ let (ty, poly_trait_ref) = self.get_ptr_vtable(vtable)?;
+ Ok(if let Some(poly_trait_ref) = poly_trait_ref {
+ let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
+ let trait_ref = self.tcx.erase_regions(trait_ref);
+ self.tcx.vtable_entries(trait_ref)
+ } else {
+ TyCtxt::COMMON_VTABLE_ENTRIES
+ })
}
- /// Returns the drop fn instance as well as the actual dynamic type.
- 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(
+ pub fn get_vtable_size_and_align(
&self,
vtable: Pointer<Option<M::Provenance>>,
) -> InterpResult<'tcx, (Size, Align)> {
- let pointer_size = self.pointer_size();
- // We check for `size = 3 * ptr_size`, which covers the drop fn (unused here),
- // the size, and the align (which we read below).
- 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 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)
+ let (ty, _trait_ref) = self.get_ptr_vtable(vtable)?;
+ let layout = self.layout_of(ty)?;
+ assert!(!layout.is_unsized(), "there are no vtables for unsized types");
+ Ok((layout.size, layout.align.abi))
}
}
match tail.kind() {
ty::Dynamic(..) => {
let vtable = self.ecx.scalar_to_ptr(meta.unwrap_meta())?;
- // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines.
- try_validation!(
- self.ecx.check_ptr_access_align(
- 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,
- err_ub!(DanglingIntPointer(..)) |
- err_ub!(PointerUseAfterFree(..)) =>
- { "dangling vtable pointer in wide pointer" },
- err_ub!(AlignmentCheckFailed { .. }) =>
- { "unaligned vtable pointer in wide pointer" },
- err_ub!(PointerOutOfBounds { .. }) =>
- { "too small vtable" },
- );
- try_validation!(
- self.ecx.read_drop_type_from_vtable(vtable),
+ // Make sure it is a genuine vtable pointer.
+ let (_ty, _trait) = try_validation!(
+ self.ecx.get_ptr_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" },
+ err_ub!(InvalidVtablePointer(..)) =>
+ { "{vtable}" } expected { "a vtable pointer" },
);
- // FIXME: More checks for the vtable.
+ // FIXME: check if the type/trait match what ty::Dynamic says?
}
ty::Slice(..) | ty::Str => {
let _len = try_validation!(
let _fn = try_validation!(
self.ecx.get_ptr_fn(ptr),
self.path,
- err_ub!(DanglingIntPointer(0, _)) =>
- { "a null function pointer" },
err_ub!(DanglingIntPointer(..)) |
err_ub!(InvalidFunctionPointer(..)) =>
- { "{:x}", value } expected { "a function pointer" },
+ { "{ptr}" } expected { "a function pointer" },
);
// FIXME: Check if the signature matches
} else {
// unsized values are never immediate, so we can assert_mem_place
let op = v.to_op_for_read(self.ecx())?;
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);
// recurse with the inner type
return self.visit_field(&v, 0, &$value_trait::from_op(&inner_mplace.into()));
use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
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_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed};
}
/// 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!
Ub(String),
/// Unreachable code was executed.
PointerArithOverflow,
/// Invalid metadata in a wide pointer (using `str` to avoid allocations).
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.
UnterminatedCString(Pointer),
/// Dereferencing a dangling pointer after it got freed.
InvalidTag(Scalar),
/// Using a pointer-not-to-a-function as function pointer.
InvalidFunctionPointer(Pointer),
+ /// Using a pointer-not-to-a-vtable as vtable pointer.
+ InvalidVtablePointer(Pointer),
/// Using a string that is not valid UTF-8,
InvalidStr(std::str::Utf8Error),
/// Using uninitialized data where it is not allowed.
UninhabitedEnumVariantWritten,
}
-impl fmt::Display for UndefinedBehaviorInfo<'_> {
+impl fmt::Display for UndefinedBehaviorInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use UndefinedBehaviorInfo::*;
match self {
RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"),
PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
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!(
f,
"reading a null-terminated string starting at {p:?} with no null found before end of allocation",
InvalidFunctionPointer(p) => {
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}"),
InvalidUninitBytes(Some((alloc, info))) => write!(
f,
pub enum InterpError<'tcx> {
/// 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
/// but the interpreter is not sure).
Unsupported(UnsupportedOpInfo),
+++ /dev/null
-// 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);
-}
--> $DIR/ub-incorrect-vtable.rs:19:14
|
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
--> $DIR/ub-incorrect-vtable.rs:24:14
|
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
- --> $DIR/ub-incorrect-vtable.rs:34:1
+ --> $DIR/ub-incorrect-vtable.rs:33:1
|
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 raw bytes of the constant (size: 8, align: 4) {
}
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> =
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 raw bytes of the constant (size: 8, align: 4) {
╾─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`.
--> $DIR/ub-incorrect-vtable.rs:19:14
|
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
--> $DIR/ub-incorrect-vtable.rs:24:14
|
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
- --> $DIR/ub-incorrect-vtable.rs:34:1
+ --> $DIR/ub-incorrect-vtable.rs:33:1
|
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 raw bytes of the constant (size: 16, align: 8) {
}
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> =
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 raw bytes of the constant (size: 16, align: 8) {
╾───────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`.
const INVALID_VTABLE_ALIGNMENT: &dyn Trait =
unsafe { std::mem::transmute((&92u8, &[0usize, 1usize, 1000usize])) };
//~^ 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 =
unsafe { std::mem::transmute((&92u8, &[1usize, usize::MAX, 1usize])) };
//~^ ERROR evaluation of constant value failed
-//~| invalid vtable: size is bigger than largest supported object
+//~| does not point to a vtable
#[repr(transparent)]
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) {}
const INVALID_VTABLE_ALIGNMENT_UB: W<&dyn Trait> =
unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), 1usize, 1000usize))) };
//~^^ 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> =
unsafe { std::mem::transmute((&92u8, &(drop_me as fn(*mut usize), usize::MAX, 1usize))) };
//~^^ 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() {}
--> $DIR/ub-ref-ptr.rs:56:1
|
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 raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-ref-ptr.rs:60:1
|
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 raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-ref-ptr.rs:62:1
|
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 raw bytes of the constant (size: 4, align: 4) {
--> $DIR/ub-ref-ptr.rs:56:1
|
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 raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-ref-ptr.rs:60:1
|
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 raw bytes of the constant (size: 8, align: 8) {
--> $DIR/ub-ref-ptr.rs:62:1
|
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 raw bytes of the constant (size: 8, align: 8) {
|
= 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) {
- ╾─alloc3──╼ ╾─alloc6──╼ │ ╾──╼╾──╼
+ ╾─alloc3──╼ ╾─alloc4──╼ │ ╾──╼╾──╼
}
error: aborting due to previous error
|
= 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) {
- ╾───────alloc3────────╼ ╾───────alloc6────────╼ │ ╾──────╼╾──────╼
+ ╾───────alloc3────────╼ ╾───────alloc4────────╼ │ ╾──────╼╾──────╼
}
error: aborting due to previous error
--> $DIR/ub-wide-ptr.rs:117:1
|
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 raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-wide-ptr.rs:120:1
|
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 raw bytes of the constant (size: 8, align: 4) {
--> $DIR/ub-wide-ptr.rs:123:1
|
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 raw bytes of the constant (size: 8, align: 4) {
╾allocN─╼ 04 00 00 00 │ ╾──╼....
}
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:125:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:125:57
|
LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered unaligned vtable pointer in wide 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─╼ │ ╾──╼╾──╼
- }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:127:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:128:57
|
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)
- |
- = 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─╼ │ ╾──╼╾──╼
- }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:129:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:131:56
|
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)
- |
- = 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─╼ │ ╾──╼╾──╼
- }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
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]))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 raw bytes of the constant (size: 8, align: 4) {
}
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) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
}
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)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 raw bytes of the constant (size: 8, align: 4) {
}
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)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 raw bytes of the constant (size: 8, align: 4) {
}
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))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
- --> $DIR/ub-wide-ptr.rs:151:5
+ --> $DIR/ub-wide-ptr.rs:154:5
|
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
--> $DIR/ub-wide-ptr.rs:117:1
|
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 raw bytes of the constant (size: 16, align: 8) {
--> $DIR/ub-wide-ptr.rs:120:1
|
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 raw bytes of the constant (size: 16, align: 8) {
--> $DIR/ub-wide-ptr.rs:123:1
|
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 raw bytes of the constant (size: 16, align: 8) {
╾──────allocN───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........
}
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:125:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:125:57
|
LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered unaligned vtable pointer in wide 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───────╼ │ ╾──────╼╾──────╼
- }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:127:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:128:57
|
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)
- |
- = 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───────╼ │ ╾──────╼╾──────╼
- }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
-error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-wide-ptr.rs:129:1
+error[E0080]: evaluation of constant value failed
+ --> $DIR/ub-wide-ptr.rs:131:56
|
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)
- |
- = 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───────╼ │ ╾──────╼╾──────╼
- }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using allocN as vtable pointer but it does not point to a vtable
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]))) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 raw bytes of the constant (size: 16, align: 8) {
}
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) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
}
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)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 raw bytes of the constant (size: 16, align: 8) {
}
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)) };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 raw bytes of the constant (size: 16, align: 8) {
}
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))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
- --> $DIR/ub-wide-ptr.rs:151:5
+ --> $DIR/ub-wide-ptr.rs:154:5
|
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
const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
//~^ ERROR it is undefined behavior to use this value
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])) };
-//~^ 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])) };
-//~^ 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]))) };
//~^ ERROR it is undefined behavior to use this value
--> $DIR/issue-79690.rs:30:1
|
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 raw bytes of the constant (size: 16, align: 8) {
- ╾───────alloc3────────╼ ╾───────alloc6────────╼ │ ╾──────╼╾──────╼
+ ╾───────alloc3────────╼ ╾───────alloc4────────╼ │ ╾──────╼╾──────╼
}
error: aborting due to previous error
|
= 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) {
- ╾─alloc7──╼ ╾─alloc9──╼ │ ╾──╼╾──╼
+ ╾─alloc7──╼ ╾─alloc8──╼ │ ╾──╼╾──╼
}
error[E0080]: it is undefined behavior to use this value
|
= 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) {
- ╾─alloc11─╼ │ ╾──╼
+ ╾─alloc10─╼ │ ╾──╼
}
warning: skipping const checks
|
= 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) {
- ╾───────alloc7────────╼ ╾───────alloc9────────╼ │ ╾──────╼╾──────╼
+ ╾───────alloc7────────╼ ╾───────alloc8────────╼ │ ╾──────╼╾──────╼
}
error[E0080]: it is undefined behavior to use this value
|
= 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) {
- ╾───────alloc11───────╼ │ ╾──────╼
+ ╾───────alloc10───────╼ │ ╾──────╼
}
warning: skipping const checks