about summary refs log tree commit diff
path: root/compiler/rustc_middle
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-08-26 21:50:09 +0000
committerbors <bors@rust-lang.org>2022-08-26 21:50:09 +0000
commit2b443a8d97ff1f26c35e4bcf682bf9a89e8a66d2 (patch)
treef8fda39334d16175c69f121ad282df2f9d92e9fd /compiler/rustc_middle
parentc07a8b4e09f356c7468b69c50cac7fc5b5000b8a (diff)
parent62b6a8b7b84ebaa375bd2b3a2f1df75b640be0ab (diff)
downloadrust-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.rs48
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs133
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs8
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