diff options
| author | bors <bors@rust-lang.org> | 2022-08-26 21:50:09 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-08-26 21:50:09 +0000 |
| commit | 2b443a8d97ff1f26c35e4bcf682bf9a89e8a66d2 (patch) | |
| tree | f8fda39334d16175c69f121ad282df2f9d92e9fd /compiler/rustc_middle | |
| parent | c07a8b4e09f356c7468b69c50cac7fc5b5000b8a (diff) | |
| parent | 62b6a8b7b84ebaa375bd2b3a2f1df75b640be0ab (diff) | |
| download | rust-2b443a8d97ff1f26c35e4bcf682bf9a89e8a66d2.tar.gz rust-2b443a8d97ff1f26c35e4bcf682bf9a89e8a66d2.zip | |
Auto merge of #100043 - RalfJung:scalar-always-init, r=RalfJung
interpret: remove support for uninitialized scalars With Miri no longer supporting `-Zmiri-allow-uninit-numbers`, we no longer need to support storing uninit data in a `Scalar`. We anyway already only use this representation for types with *initialized* `Scalar` layout (and we have to, due to partial initialization), so let's get rid of the `ScalarMaybeUninit` type entirely. I tried to stage this into meaningful commits, but the one that changes `read_immediate` to always trigger UB on uninit is the largest chunk of the PR and I don't see how it could be subdivided. Fixes https://github.com/rust-lang/miri/issues/2187 r? `@oli-obk`
Diffstat (limited to 'compiler/rustc_middle')
| -rw-r--r-- | compiler/rustc_middle/src/mir/interpret/allocation.rs | 48 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/interpret/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/mir/interpret/value.rs | 133 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/vtable.rs | 8 |
4 files changed, 17 insertions, 174 deletions
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index db7e0fb8a3b..3f618106525 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -16,8 +16,8 @@ use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ read_target_uint, write_target_uint, AllocId, InterpError, InterpResult, Pointer, Provenance, - ResourceExhaustionInfo, Scalar, ScalarMaybeUninit, ScalarSizeMismatch, UndefinedBehaviorInfo, - UninitBytesAccess, UnsupportedOpInfo, + ResourceExhaustionInfo, Scalar, ScalarSizeMismatch, UndefinedBehaviorInfo, UninitBytesAccess, + UnsupportedOpInfo, }; use crate::ty; @@ -415,25 +415,10 @@ impl<Prov: Provenance, Extra> Allocation<Prov, Extra> { /// Reading and writing. impl<Prov: Provenance, Extra> Allocation<Prov, Extra> { - /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a - /// relocation. If `allow_uninit`/`allow_ptr` is `false`, also enforces that the memory in the - /// given range contains no uninitialized bytes/relocations. - pub fn check_bytes( - &self, - cx: &impl HasDataLayout, - range: AllocRange, - allow_uninit: bool, - allow_ptr: bool, - ) -> AllocResult { - // Check bounds and relocations on the edges. - self.get_bytes_with_uninit_and_ptr(cx, range)?; - // Check uninit and ptr. - if !allow_uninit { - self.check_init(range)?; - } - if !allow_ptr { - self.check_relocations(cx, range)?; - } + /// Validates that this memory range is initiailized and contains no relocations. + pub fn check_bytes(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult { + // This implicitly does all the checking we are asking for. + self.get_bytes(cx, range)?; Ok(()) } @@ -452,16 +437,14 @@ impl<Prov: Provenance, Extra> Allocation<Prov, Extra> { cx: &impl HasDataLayout, range: AllocRange, read_provenance: bool, - ) -> AllocResult<ScalarMaybeUninit<Prov>> { + ) -> AllocResult<Scalar<Prov>> { if read_provenance { assert_eq!(range.size, cx.data_layout().pointer_size); } // First and foremost, if anything is uninit, bail. if self.is_init(range).is_err() { - // This inflates uninitialized bytes to the entire scalar, even if only a few - // bytes are uninitialized. - return Ok(ScalarMaybeUninit::Uninit); + return Err(AllocError::InvalidUninitBytes(None)); } // If we are doing a pointer read, and there is a relocation exactly where we @@ -471,7 +454,7 @@ impl<Prov: Provenance, Extra> Allocation<Prov, Extra> { let bytes = self.get_bytes_even_more_internal(range); let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap(); let ptr = Pointer::new(prov, Size::from_bytes(bits)); - return Ok(ScalarMaybeUninit::from_pointer(ptr, cx)); + return Ok(Scalar::from_pointer(ptr, cx)); } // If we are *not* reading a pointer, and we can just ignore relocations, @@ -480,7 +463,7 @@ impl<Prov: Provenance, Extra> Allocation<Prov, Extra> { // We just strip provenance. let bytes = self.get_bytes_even_more_internal(range); let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap(); - return Ok(ScalarMaybeUninit::Scalar(Scalar::from_uint(bits, range.size))); + return Ok(Scalar::from_uint(bits, range.size)); } // It's complicated. Better make sure there is no provenance anywhere. @@ -492,7 +475,7 @@ impl<Prov: Provenance, Extra> Allocation<Prov, Extra> { // underlying bits. let bytes = self.get_bytes(cx, range)?; let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap(); - Ok(ScalarMaybeUninit::Scalar(Scalar::from_uint(bits, range.size))) + Ok(Scalar::from_uint(bits, range.size)) } /// Writes a *non-ZST* scalar. @@ -507,17 +490,10 @@ impl<Prov: Provenance, Extra> Allocation<Prov, Extra> { &mut self, cx: &impl HasDataLayout, range: AllocRange, - val: ScalarMaybeUninit<Prov>, + val: Scalar<Prov>, ) -> AllocResult { assert!(self.mutability == Mutability::Mut); - let val = match val { - ScalarMaybeUninit::Scalar(scalar) => scalar, - ScalarMaybeUninit::Uninit => { - return self.write_uninit(cx, range); - } - }; - // `to_bits_or_ptr_internal` is the right method because we just want to store this data // as-is into memory. let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size)? { diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 967f8ece16c..93fe7e63710 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -124,7 +124,7 @@ pub use self::error::{ UninitBytesAccess, UnsupportedOpInfo, }; -pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit}; +pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar}; pub use self::allocation::{ alloc_range, AllocRange, Allocation, ConstAllocation, InitChunk, InitChunkIter, InitMask, diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index a1c111ae372..ba56c5267df 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -504,139 +504,6 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> { } } -#[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, HashStable, Hash)] -pub enum ScalarMaybeUninit<Prov = AllocId> { - Scalar(Scalar<Prov>), - Uninit, -} - -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(ScalarMaybeUninit, 24); - -impl<Prov> From<Scalar<Prov>> for ScalarMaybeUninit<Prov> { - #[inline(always)] - fn from(s: Scalar<Prov>) -> Self { - ScalarMaybeUninit::Scalar(s) - } -} - -// We want the `Debug` output to be readable as it is used by `derive(Debug)` for -// all the Miri types. -impl<Prov: Provenance> fmt::Debug for ScalarMaybeUninit<Prov> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ScalarMaybeUninit::Uninit => write!(f, "<uninitialized>"), - ScalarMaybeUninit::Scalar(s) => write!(f, "{:?}", s), - } - } -} - -impl<Prov: Provenance> fmt::LowerHex for ScalarMaybeUninit<Prov> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ScalarMaybeUninit::Uninit => write!(f, "uninitialized bytes"), - ScalarMaybeUninit::Scalar(s) => write!(f, "{:x}", s), - } - } -} - -impl<Prov> ScalarMaybeUninit<Prov> { - #[inline] - pub fn from_pointer(ptr: Pointer<Prov>, cx: &impl HasDataLayout) -> Self { - ScalarMaybeUninit::Scalar(Scalar::from_pointer(ptr, cx)) - } - - #[inline] - pub fn from_maybe_pointer(ptr: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self { - ScalarMaybeUninit::Scalar(Scalar::from_maybe_pointer(ptr, cx)) - } - - #[inline] - pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar<Prov>> { - match self { - ScalarMaybeUninit::Scalar(scalar) => Ok(scalar), - ScalarMaybeUninit::Uninit => throw_ub!(InvalidUninitBytes(None)), - } - } -} - -impl<'tcx, Prov: Provenance> ScalarMaybeUninit<Prov> { - #[inline(always)] - pub fn to_pointer(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, Pointer<Option<Prov>>> { - self.check_init()?.to_pointer(cx) - } - - #[inline(always)] - pub fn to_bool(self) -> InterpResult<'tcx, bool> { - self.check_init()?.to_bool() - } - - #[inline(always)] - pub fn to_char(self) -> InterpResult<'tcx, char> { - self.check_init()?.to_char() - } - - #[inline(always)] - pub fn to_f32(self) -> InterpResult<'tcx, Single> { - self.check_init()?.to_f32() - } - - #[inline(always)] - pub fn to_f64(self) -> InterpResult<'tcx, Double> { - self.check_init()?.to_f64() - } - - #[inline(always)] - pub fn to_u8(self) -> InterpResult<'tcx, u8> { - self.check_init()?.to_u8() - } - - #[inline(always)] - pub fn to_u16(self) -> InterpResult<'tcx, u16> { - self.check_init()?.to_u16() - } - - #[inline(always)] - pub fn to_u32(self) -> InterpResult<'tcx, u32> { - self.check_init()?.to_u32() - } - - #[inline(always)] - pub fn to_u64(self) -> InterpResult<'tcx, u64> { - self.check_init()?.to_u64() - } - - #[inline(always)] - pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { - self.check_init()?.to_machine_usize(cx) - } - - #[inline(always)] - pub fn to_i8(self) -> InterpResult<'tcx, i8> { - self.check_init()?.to_i8() - } - - #[inline(always)] - pub fn to_i16(self) -> InterpResult<'tcx, i16> { - self.check_init()?.to_i16() - } - - #[inline(always)] - pub fn to_i32(self) -> InterpResult<'tcx, i32> { - self.check_init()?.to_i32() - } - - #[inline(always)] - pub fn to_i64(self) -> InterpResult<'tcx, i64> { - self.check_init()?.to_i64() - } - - #[inline(always)] - pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> { - self.check_init()?.to_machine_isize(cx) - } -} - /// Gets the bytes of a constant slice value. pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) -> &'tcx [u8] { if let ConstValue::Slice { data, start, end } = val { diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 04a9fd1f713..5ca51c25a9c 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -1,7 +1,7 @@ use std::convert::TryFrom; use std::fmt; -use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar, ScalarMaybeUninit}; +use crate::mir::interpret::{alloc_range, AllocId, Allocation, Pointer, Scalar}; use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt}; use rustc_ast::Mutability; @@ -87,7 +87,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( let instance = ty::Instance::resolve_drop_in_place(tcx, ty); let fn_alloc_id = tcx.create_fn_alloc(instance); let fn_ptr = Pointer::from(fn_alloc_id); - ScalarMaybeUninit::from_pointer(fn_ptr, &tcx) + Scalar::from_pointer(fn_ptr, &tcx) } VtblEntry::MetadataSize => Scalar::from_uint(size, ptr_size).into(), VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size).into(), @@ -97,14 +97,14 @@ pub(super) fn vtable_allocation_provider<'tcx>( let instance = instance.polymorphize(tcx); let fn_alloc_id = tcx.create_fn_alloc(instance); let fn_ptr = Pointer::from(fn_alloc_id); - ScalarMaybeUninit::from_pointer(fn_ptr, &tcx) + Scalar::from_pointer(fn_ptr, &tcx) } VtblEntry::TraitVPtr(trait_ref) => { let super_trait_ref = trait_ref .map_bound(|trait_ref| ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); let supertrait_alloc_id = tcx.vtable_allocation((ty, Some(super_trait_ref))); let vptr = Pointer::from(supertrait_alloc_id); - ScalarMaybeUninit::from_pointer(vptr, &tcx) + Scalar::from_pointer(vptr, &tcx) } }; vtable |
