From cc0fbdffe7db21649f45b3407ff9766636727690 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 21 Dec 2019 23:55:34 +0100 Subject: [PATCH 01/13] Automatically prefer integer addresses for zst MPlace --- src/librustc_mir/const_eval/eval_queries.rs | 4 +-- src/librustc_mir/interpret/operand.rs | 30 ++++----------------- src/librustc_mir/interpret/place.rs | 19 ++++++------- src/librustc_mir/interpret/terminator.rs | 2 +- src/librustc_mir/interpret/validity.rs | 11 +++----- src/librustc_mir/interpret/visitor.rs | 10 ++----- src/librustc_mir/transform/const_prop.rs | 3 ++- 7 files changed, 26 insertions(+), 53 deletions(-) diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index dbeb75b60c290..8c41f7d1e61f6 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -115,7 +115,7 @@ pub(super) fn op_to_const<'tcx>( // by-val is if we are in const_field, i.e., if this is (a field of) something that we // "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or // structs containing such. - op.try_as_mplace() + op.try_as_mplace(ecx) }; let val = match immediate { Ok(mplace) => { @@ -132,7 +132,7 @@ pub(super) fn op_to_const<'tcx>( // `Immediate` is when we are called from `const_field`, and that `Immediate` // comes from a constant so it can happen have `Undef`, because the indirect // memory that was read had undefined bytes. - let mplace = op.assert_mem_place(); + let mplace = op.assert_mem_place(ecx); let ptr = mplace.ptr.assert_ptr(); let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); ConstValue::ByRef { alloc, offset: ptr.offset } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index def979b63b52a..00aecf74c7d3d 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -267,7 +267,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, op: OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - match op.try_as_mplace() { + match op.try_as_mplace(self) { Ok(mplace) => Ok(self.force_mplace_ptr(mplace)?.into()), Err(imm) => Ok(imm.into()), // Nothing to cast/force } @@ -335,7 +335,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, src: OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, Result, MPlaceTy<'tcx, M::PointerTag>>> { - Ok(match src.try_as_mplace() { + Ok(match src.try_as_mplace(self) { Ok(mplace) => { if let Some(val) = self.try_read_immediate_from_mplace(mplace)? { Ok(val) @@ -383,7 +383,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { op: OpTy<'tcx, M::PointerTag>, field: u64, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { - let base = match op.try_as_mplace() { + let base = match op.try_as_mplace(self) { Ok(mplace) => { // The easy case let field = self.mplace_field(mplace, field)?; @@ -420,7 +420,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { variant: VariantIdx, ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { // Downcasts only change the layout - Ok(match op.try_as_mplace() { + Ok(match op.try_as_mplace(self) { Ok(mplace) => self.mplace_downcast(mplace, variant)?.into(), Err(..) => { let layout = op.layout.for_variant(self, variant); @@ -439,30 +439,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Field(field, _) => self.operand_field(base, field.index() as u64)?, Downcast(_, variant) => self.operand_downcast(base, variant)?, Deref => self.deref_operand(base)?.into(), - ConstantIndex { .. } | Index(_) if base.layout.is_zst() => { - OpTy { - op: Operand::Immediate(Scalar::zst().into()), - // the actual index doesn't matter, so we just pick a convenient one like 0 - layout: base.layout.field(self, 0)?, - } - } - Subslice { from, to, from_end } if base.layout.is_zst() => { - let elem_ty = if let ty::Array(elem_ty, _) = base.layout.ty.kind { - elem_ty - } else { - bug!("slices shouldn't be zero-sized"); - }; - assert!(!from_end, "arrays shouldn't be subsliced from the end"); - - OpTy { - op: Operand::Immediate(Scalar::zst().into()), - layout: self.layout_of(self.tcx.mk_array(elem_ty, (to - from) as u64))?, - } - } Subslice { .. } | ConstantIndex { .. } | Index(_) => { // The rest should only occur as mplace, we do not use Immediates for types // allowing such operations. This matches place_projection forcing an allocation. - let mplace = base.assert_mem_place(); + let mplace = base.assert_mem_place(self); self.mplace_projection(mplace, proj_elem)?.into() } }) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index f4ac7de852af0..7fbe691f183cc 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -200,16 +200,17 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { // These are defined here because they produce a place. impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { #[inline(always)] - pub fn try_as_mplace(self) -> Result, ImmTy<'tcx, Tag>> { + pub fn try_as_mplace(self, cx: &impl HasDataLayout) -> Result, ImmTy<'tcx, Tag>> { match *self { Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }), + Operand::Immediate(_) if self.layout.is_zst() => Ok(MPlaceTy::dangling(self.layout, cx)), Operand::Immediate(imm) => Err(ImmTy { imm, layout: self.layout }), } } #[inline(always)] - pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> { - self.try_as_mplace().unwrap() + pub fn assert_mem_place(self, cx: &impl HasDataLayout) -> MPlaceTy<'tcx, Tag> { + self.try_as_mplace(cx).unwrap() } } @@ -305,7 +306,7 @@ where /// On success, returns `None` for zero-sized accesses (where nothing else is /// left to do) and a `Pointer` to use for the actual access otherwise. #[inline] - pub fn check_mplace_access( + pub(super) fn check_mplace_access( &self, place: MPlaceTy<'tcx, M::PointerTag>, size: Option, @@ -338,7 +339,7 @@ where /// Force `place.ptr` to a `Pointer`. /// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot. - pub fn force_mplace_ptr( + pub(super) fn force_mplace_ptr( &self, mut place: MPlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { @@ -415,7 +416,7 @@ where // Iterates over all fields of an array. Much more efficient than doing the // same by repeatedly calling `mplace_array`. - pub fn mplace_array_fields( + pub(super) fn mplace_array_fields( &self, base: MPlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx, impl Iterator>> + 'tcx> @@ -430,7 +431,7 @@ where Ok((0..len).map(move |i| base.offset(i * stride, None, layout, dl))) } - pub fn mplace_subslice( + fn mplace_subslice( &self, base: MPlaceTy<'tcx, M::PointerTag>, from: u64, @@ -471,7 +472,7 @@ where base.offset(from_offset, meta, layout, self) } - pub fn mplace_downcast( + pub(super) fn mplace_downcast( &self, base: MPlaceTy<'tcx, M::PointerTag>, variant: VariantIdx, @@ -482,7 +483,7 @@ where } /// Project into an mplace - pub fn mplace_projection( + pub(super) fn mplace_projection( &self, base: MPlaceTy<'tcx, M::PointerTag>, proj_elem: &mir::PlaceElem<'tcx>, diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index a28bb539fd070..37dcab512b991 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -378,7 +378,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } None => { // Unsized self. - args[0].assert_mem_place() + args[0].assert_mem_place(self) } }; // Find and consult vtable diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 7b82bed2e7a61..73f479ede769d 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -571,12 +571,9 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> ) -> InterpResult<'tcx> { match op.layout.ty.kind { ty::Str => { - let mplace = op.assert_mem_place(); // strings are never immediate - try_validation!( - self.ecx.read_str(mplace), - "uninitialized or non-UTF-8 data in str", - self.path - ); + let mplace = op.assert_mem_place(self.ecx); // strings are never immediate + try_validation!(self.ecx.read_str(mplace), + "uninitialized or non-UTF-8 data in str", self.path); } ty::Array(tys, ..) | ty::Slice(tys) if { @@ -604,7 +601,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> return Ok(()); } // non-ZST array cannot be immediate, slices are never immediate - let mplace = op.assert_mem_place(); + let mplace = op.assert_mem_place(self.ecx); // This is the length of the array/slice. let len = mplace.len(self.ecx)?; // zero length slices have nothing to be checked diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index 2cfcf0ff06d0f..d2594e8707104 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -223,7 +223,7 @@ macro_rules! make_value_visitor { match v.layout().ty.kind { ty::Dynamic(..) => { // immediate trait objects are not a thing - let dest = v.to_op(self.ecx())?.assert_mem_place(); + let dest = v.to_op(self.ecx())?.assert_mem_place(self.ecx()); let inner = self.ecx().unpack_dyn_trait(dest)?.1; trace!("walk_value: dyn object layout: {:#?}", inner.layout); // recurse with the inner type @@ -292,13 +292,7 @@ macro_rules! make_value_visitor { }, layout::FieldPlacement::Array { .. } => { // Let's get an mplace first. - let mplace = if v.layout().is_zst() { - // it's a ZST, the memory content cannot matter - MPlaceTy::dangling(v.layout(), self.ecx()) - } else { - // non-ZST array/slice/str cannot be immediate - v.to_op(self.ecx())?.assert_mem_place() - }; + let mplace = v.to_op(self.ecx())?.assert_mem_place(self.ecx()); // Now we can go over all the fields. let iter = self.ecx().mplace_array_fields(mplace)? .map(|f| f.and_then(|f| { diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 6b0f7be86841e..d5d56b36cf4c3 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -707,7 +707,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { ScalarMaybeUndef::Scalar(r), )) => l.is_bits() && r.is_bits(), interpret::Operand::Indirect(_) if mir_opt_level >= 2 => { - intern_const_alloc_recursive(&mut self.ecx, None, op.assert_mem_place()) + let mplace = op.assert_mem_place(&self.ecx); + intern_const_alloc_recursive(&mut self.ecx, None, mplace) .expect("failed to intern alloc"); true } From 5b770b080fab5a64875ffb10deff9e6d14950fc0 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 00:33:15 +0100 Subject: [PATCH 02/13] Remove a ZST special casing that is not necessary anymore --- src/librustc_mir/interpret/validity.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 73f479ede769d..786909731531f 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -596,15 +596,11 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> { // Optimized handling for arrays of integer/float type. - // bailing out for zsts is ok, since the array element type can only be int/float - if op.layout.is_zst() { - return Ok(()); - } - // non-ZST array cannot be immediate, slices are never immediate + // Arrays cannot be immediate, slices are never immediate. let mplace = op.assert_mem_place(self.ecx); // This is the length of the array/slice. let len = mplace.len(self.ecx)?; - // zero length slices have nothing to be checked + // Zero length slices have nothing to be checked. if len == 0 { return Ok(()); } From 4a5c35bc4490ecf5b06d311917ac64be63673d3c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 00:35:56 +0100 Subject: [PATCH 03/13] Fix an ICE happening due code assuming that `MPlaceTy` cannot have integer addresses --- src/librustc_mir/const_eval/eval_queries.rs | 18 ++------------ src/librustc_mir/interpret/place.rs | 26 ++++++++++++++++++--- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 8c41f7d1e61f6..f28517c667265 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -118,25 +118,11 @@ pub(super) fn op_to_const<'tcx>( op.try_as_mplace(ecx) }; let val = match immediate { - Ok(mplace) => { - let ptr = mplace.ptr.assert_ptr(); - let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); - ConstValue::ByRef { alloc, offset: ptr.offset } - } + Ok(mplace) => mplace.to_const_value(ecx.tcx.tcx), // see comment on `let try_as_immediate` above Err(ImmTy { imm: Immediate::Scalar(x), .. }) => match x { ScalarMaybeUndef::Scalar(s) => ConstValue::Scalar(s), - ScalarMaybeUndef::Undef => { - // When coming out of "normal CTFE", we'll always have an `Indirect` operand as - // argument and we will not need this. The only way we can already have an - // `Immediate` is when we are called from `const_field`, and that `Immediate` - // comes from a constant so it can happen have `Undef`, because the indirect - // memory that was read had undefined bytes. - let mplace = op.assert_mem_place(ecx); - let ptr = mplace.ptr.assert_ptr(); - let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); - ConstValue::ByRef { alloc, offset: ptr.offset } - } + ScalarMaybeUndef::Undef => op.assert_mem_place(ecx).to_const_value(ecx.tcx.tcx), }, Err(ImmTy { imm: Immediate::ScalarPair(a, b), .. }) => { let (data, start) = match a.not_undef().unwrap() { diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 7fbe691f183cc..54a692c66e3bc 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -6,12 +6,13 @@ use std::convert::TryFrom; use std::hash::Hash; use rustc::mir; -use rustc::mir::interpret::truncate; +use rustc::mir::interpret::{truncate, ConstValue}; use rustc::ty::layout::{ self, Align, HasDataLayout, LayoutOf, PrimitiveExt, Size, TyLayout, VariantIdx, }; use rustc::ty::TypeFoldable; use rustc::ty::{self, Ty}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc_macros::HashStable; use super::{ @@ -195,15 +196,34 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { _ => bug!("vtable not supported on type {:?}", self.layout.ty), } } + + #[inline(always)] + pub fn to_const_value(self, tcx: TyCtxt<'tcx>) -> ConstValue<'tcx> { + match self.mplace.ptr { + Scalar::Ptr(ptr) => { + let alloc = tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); + ConstValue::ByRef { alloc, offset: ptr.offset } + } + Scalar::Raw { data, .. } => { + assert_eq!(data, self.layout.align.abi.bytes().into()); + ConstValue::Scalar(Scalar::zst()) + } + } + } } // These are defined here because they produce a place. impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { #[inline(always)] - pub fn try_as_mplace(self, cx: &impl HasDataLayout) -> Result, ImmTy<'tcx, Tag>> { + pub fn try_as_mplace( + self, + cx: &impl HasDataLayout, + ) -> Result, ImmTy<'tcx, Tag>> { match *self { Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }), - Operand::Immediate(_) if self.layout.is_zst() => Ok(MPlaceTy::dangling(self.layout, cx)), + Operand::Immediate(_) if self.layout.is_zst() => { + Ok(MPlaceTy::dangling(self.layout, cx)) + } Operand::Immediate(imm) => Err(ImmTy { imm, layout: self.layout }), } } From cac6f4c12db5fadff650267a8456d5835d19b136 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 26 Dec 2019 23:32:34 +0100 Subject: [PATCH 04/13] Move `to_const_value` from `MPlaceTy` to its only use site --- src/librustc_mir/const_eval/eval_queries.rs | 15 +++++++++++++-- src/librustc_mir/interpret/place.rs | 17 +---------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index f28517c667265..b0add10dcac43 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -117,12 +117,23 @@ pub(super) fn op_to_const<'tcx>( // structs containing such. op.try_as_mplace(ecx) }; + + let to_const_value = |mplace: MPlaceTy<'_>| match mplace.ptr { + Scalar::Ptr(ptr) => { + let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); + ConstValue::ByRef { alloc, offset: ptr.offset } + } + Scalar::Raw { data, .. } => { + assert_eq!(data, mplace.layout.align.abi.bytes().into()); + ConstValue::Scalar(Scalar::zst()) + } + }; let val = match immediate { - Ok(mplace) => mplace.to_const_value(ecx.tcx.tcx), + Ok(mplace) => to_const_value(mplace), // see comment on `let try_as_immediate` above Err(ImmTy { imm: Immediate::Scalar(x), .. }) => match x { ScalarMaybeUndef::Scalar(s) => ConstValue::Scalar(s), - ScalarMaybeUndef::Undef => op.assert_mem_place(ecx).to_const_value(ecx.tcx.tcx), + ScalarMaybeUndef::Undef => to_const_value(op.assert_mem_place(ecx)), }, Err(ImmTy { imm: Immediate::ScalarPair(a, b), .. }) => { let (data, start) = match a.not_undef().unwrap() { diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 54a692c66e3bc..c8499d845dd13 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -6,13 +6,12 @@ use std::convert::TryFrom; use std::hash::Hash; use rustc::mir; -use rustc::mir::interpret::{truncate, ConstValue}; +use rustc::mir::interpret::truncate; use rustc::ty::layout::{ self, Align, HasDataLayout, LayoutOf, PrimitiveExt, Size, TyLayout, VariantIdx, }; use rustc::ty::TypeFoldable; use rustc::ty::{self, Ty}; -use rustc::ty::{self, Ty, TyCtxt}; use rustc_macros::HashStable; use super::{ @@ -196,20 +195,6 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { _ => bug!("vtable not supported on type {:?}", self.layout.ty), } } - - #[inline(always)] - pub fn to_const_value(self, tcx: TyCtxt<'tcx>) -> ConstValue<'tcx> { - match self.mplace.ptr { - Scalar::Ptr(ptr) => { - let alloc = tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id); - ConstValue::ByRef { alloc, offset: ptr.offset } - } - Scalar::Raw { data, .. } => { - assert_eq!(data, self.layout.align.abi.bytes().into()); - ConstValue::Scalar(Scalar::zst()) - } - } - } } // These are defined here because they produce a place. From 4fbe434c5c10d9a0550db4ae93aaac3a0ed9816e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 27 Dec 2019 00:38:10 +0100 Subject: [PATCH 05/13] Poison any `MemPlace` created from a zst Operand (or otherwise via `MPlaceTy::dangling`) so you can't get the address back out. --- src/librustc_mir/interpret/eval_context.rs | 13 ++- src/librustc_mir/interpret/intern.rs | 5 +- src/librustc_mir/interpret/mod.rs | 2 +- src/librustc_mir/interpret/place.rs | 98 ++++++++++++++++------ src/librustc_mir/interpret/snapshot.rs | 12 ++- src/librustc_mir/interpret/validity.rs | 15 ++-- 6 files changed, 102 insertions(+), 43 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 551e3e837c988..c5c2a6769e44a 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -20,7 +20,7 @@ use rustc_macros::HashStable; use rustc_span::source_map::{self, Span, DUMMY_SP}; use super::{ - Immediate, MPlaceTy, Machine, MemPlace, Memory, OpTy, Operand, Place, PlaceTy, + Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy, ScalarMaybeUndef, StackPopInfo, }; @@ -393,7 +393,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// This can fail to provide an answer for extern types. pub(super) fn size_and_align_of( &self, - metadata: Option>, + metadata: MemPlaceMeta, layout: TyLayout<'tcx>, ) -> InterpResult<'tcx, Option<(Size, Align)>> { if !layout.is_unsized() { @@ -465,14 +465,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(Some((size, align))) } ty::Dynamic(..) => { - let vtable = metadata.expect("dyn trait fat ptr must have vtable"); + let vtable = metadata.unwrap_unsized(); // Read size and align from vtable (already checks size). Ok(Some(self.read_size_and_align_from_vtable(vtable)?)) } ty::Slice(_) | ty::Str => { - let len = - metadata.expect("slice fat ptr must have length").to_machine_usize(self)?; + let len = metadata.unwrap_unsized().to_machine_usize(self)?; let elem = layout.field(self, 0)?; // Make sure the slice is not too big. @@ -818,8 +817,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { " by align({}){} ref:", mplace.align.bytes(), match mplace.meta { - Some(meta) => format!(" meta({:?})", meta), - None => String::new(), + MemPlaceMeta::Unsized(meta) => format!(" meta({:?})", meta), + MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(), } ) .unwrap(); diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index 7c6129ef30ffd..56e489d0bd590 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -193,7 +193,7 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx { // Validation has already errored on an invalid vtable pointer so we can safely not // do anything if this is not a real pointer. - if let Scalar::Ptr(vtable) = mplace.meta.unwrap() { + if let Scalar::Ptr(vtable) = mplace.meta.unwrap_unsized() { // Explicitly choose `Immutable` here, since vtables are immutable, even // if the reference of the fat pointer is mutable. self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?; @@ -226,7 +226,8 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx | (InternMode::Const, hir::Mutability::Mut) => match referenced_ty.kind { ty::Array(_, n) if n.eval_usize(self.ecx.tcx.tcx, self.ecx.param_env) == 0 => {} - ty::Slice(_) if mplace.meta.unwrap().to_machine_usize(self.ecx)? == 0 => {} + ty::Slice(_) + if mplace.meta.unwrap_unsized().to_machine_usize(self.ecx)? == 0 => {} _ => bug!("const qualif failed to prevent mutable references"), }, } diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index 0d35eae6ed08d..2e8fbb95ca2e5 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -20,7 +20,7 @@ pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one pla pub use self::eval_context::{Frame, InterpCx, LocalState, LocalValue, StackPopCleanup}; -pub use self::place::{MPlaceTy, MemPlace, Place, PlaceTy}; +pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy}; pub use self::memory::{AllocCheck, FnVal, Memory, MemoryKind}; diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index c8499d845dd13..6d848092defe5 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -20,6 +20,45 @@ use super::{ RawConst, Scalar, ScalarMaybeUndef, }; +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)] +pub enum MemPlaceMeta { + Unsized(Scalar), + /// `Sized` types or unsized `extern type` + None, + /// The address of this place may not be taken. This protects the `MemPlace` from coming from + /// a ZST Operand with a backing allocation and being converted to an integer address. This + /// should be impossible, because you can't take the address of an operand, but this is a second + /// protection layer ensuring that we don't mess up. + Poison, +} + +impl MemPlaceMeta { + pub fn unwrap_unsized(self) -> Scalar { + match self { + Self::Unsized(s) => s, + Self::None | Self::Poison => { + bug!("expected wide pointer extra data (e.g. slice length or trait object vtable)") + } + } + } + fn is_unsized(self) -> bool { + match self { + Self::Unsized(_) => true, + Self::None | Self::Poison => false, + } + } +} + +impl MemPlaceMeta { + pub fn erase_tag(self) -> MemPlaceMeta<()> { + match self { + Self::Unsized(s) => MemPlaceMeta::Unsized(s.erase_tag()), + Self::None => MemPlaceMeta::None, + Self::Poison => MemPlaceMeta::Poison, + } + } +} + #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)] pub struct MemPlace { /// A place may have an integral pointer for ZSTs, and since it might @@ -30,7 +69,7 @@ pub struct MemPlace { /// Metadata for unsized places. Interpretation is up to the type. /// Must not be present for sized types, but can be missing for unsized types /// (e.g., `extern type`). - pub meta: Option>, + pub meta: MemPlaceMeta, } #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)] @@ -88,16 +127,12 @@ impl MemPlace { #[inline] pub fn erase_tag(self) -> MemPlace { - MemPlace { - ptr: self.ptr.erase_tag(), - align: self.align, - meta: self.meta.map(Scalar::erase_tag), - } + MemPlace { ptr: self.ptr.erase_tag(), align: self.align, meta: self.meta.erase_tag() } } #[inline(always)] pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self { - MemPlace { ptr, align, meta: None } + MemPlace { ptr, align, meta: MemPlaceMeta::None } } /// Produces a Place that will error if attempted to be read from or written to @@ -116,15 +151,19 @@ impl MemPlace { #[inline(always)] pub fn to_ref(self) -> Immediate { match self.meta { - None => Immediate::Scalar(self.ptr.into()), - Some(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()), + MemPlaceMeta::None => Immediate::Scalar(self.ptr.into()), + MemPlaceMeta::Unsized(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()), + MemPlaceMeta::Poison => bug!( + "MPlaceTy::dangling may never be used to produce a \ + place that will have the address of its pointee taken" + ), } } pub fn offset( self, offset: Size, - meta: Option>, + meta: MemPlaceMeta, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Self> { Ok(MemPlace { @@ -158,7 +197,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { pub fn offset( self, offset: Size, - meta: Option>, + meta: MemPlaceMeta, layout: TyLayout<'tcx>, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Self> { @@ -175,7 +214,9 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { if self.layout.is_unsized() { // We need to consult `meta` metadata match self.layout.ty.kind { - ty::Slice(..) | ty::Str => return self.mplace.meta.unwrap().to_machine_usize(cx), + ty::Slice(..) | ty::Str => { + return self.mplace.meta.unwrap_unsized().to_machine_usize(cx); + } _ => bug!("len not supported on unsized type {:?}", self.layout.ty), } } else { @@ -191,7 +232,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { #[inline] pub(super) fn vtable(self) -> Scalar { match self.layout.ty.kind { - ty::Dynamic(..) => self.mplace.meta.unwrap(), + ty::Dynamic(..) => self.mplace.meta.unwrap_unsized(), _ => bug!("vtable not supported on type {:?}", self.layout.ty), } } @@ -276,8 +317,10 @@ where val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty; let layout = self.layout_of(pointee_type)?; let (ptr, meta) = match *val { - Immediate::Scalar(ptr) => (ptr.not_undef()?, None), - Immediate::ScalarPair(ptr, meta) => (ptr.not_undef()?, Some(meta.not_undef()?)), + Immediate::Scalar(ptr) => (ptr.not_undef()?, MemPlaceMeta::None), + Immediate::ScalarPair(ptr, meta) => { + (ptr.not_undef()?, MemPlaceMeta::Unsized(meta.not_undef()?)) + } }; let mplace = MemPlace { @@ -318,7 +361,7 @@ where ) -> InterpResult<'tcx, Option>> { let size = size.unwrap_or_else(|| { assert!(!place.layout.is_unsized()); - assert!(place.meta.is_none()); + assert!(!place.meta.is_unsized()); place.layout.size }); self.memory.check_ptr_access(place.ptr, size, place.align) @@ -411,7 +454,7 @@ where } else { // base.meta could be present; we might be accessing a sized field of an unsized // struct. - (None, offset) + (MemPlaceMeta::None, offset) }; // We do not look at `base.layout.align` nor `field_layout.align`, unlike @@ -433,7 +476,7 @@ where }; let layout = base.layout.field(self, 0)?; let dl = &self.tcx.data_layout; - Ok((0..len).map(move |i| base.offset(i * stride, None, layout, dl))) + Ok((0..len).map(move |i| base.offset(i * stride, MemPlaceMeta::None, layout, dl))) } fn mplace_subslice( @@ -466,10 +509,10 @@ where let (meta, ty) = match base.layout.ty.kind { // It is not nice to match on the type, but that seems to be the only way to // implement this. - ty::Array(inner, _) => (None, self.tcx.mk_array(inner, inner_len)), + ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(inner, inner_len)), ty::Slice(..) => { let len = Scalar::from_uint(inner_len, self.pointer_size()); - (Some(len), base.layout.ty) + (MemPlaceMeta::Unsized(len), base.layout.ty) } _ => bug!("cannot subslice non-array type: `{:?}`", base.layout.ty), }; @@ -483,7 +526,7 @@ where variant: VariantIdx, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // Downcasts only change the layout - assert!(base.meta.is_none()); + assert!(!base.meta.is_unsized()); Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base }) } @@ -977,7 +1020,7 @@ where pub fn force_allocation_maybe_sized( &mut self, place: PlaceTy<'tcx, M::PointerTag>, - meta: Option>, + meta: MemPlaceMeta, ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option)> { let (mplace, size) = match place.place { Place::Local { frame, local } => { @@ -1022,7 +1065,7 @@ where &mut self, place: PlaceTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - Ok(self.force_allocation_maybe_sized(place, None)?.0) + Ok(self.force_allocation_maybe_sized(place, MemPlaceMeta::None)?.0) } pub fn allocate( @@ -1042,8 +1085,11 @@ where ) -> MPlaceTy<'tcx, M::PointerTag> { let ptr = self.memory.allocate_static_bytes(str.as_bytes(), kind); let meta = Scalar::from_uint(str.len() as u128, self.pointer_size()); - let mplace = - MemPlace { ptr: ptr.into(), align: Align::from_bytes(1).unwrap(), meta: Some(meta) }; + let mplace = MemPlace { + ptr: ptr.into(), + align: Align::from_bytes(1).unwrap(), + meta: MemPlaceMeta::Unsized(meta), + }; let layout = self.layout_of(self.tcx.mk_static_str()).unwrap(); MPlaceTy { mplace, layout } @@ -1151,7 +1197,7 @@ where assert_eq!(align, layout.align.abi); } - let mplace = MPlaceTy { mplace: MemPlace { meta: None, ..*mplace }, layout }; + let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..*mplace }, layout }; Ok((instance, mplace)) } } diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index 6790baf31ccb2..120baaf3be68a 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -23,7 +23,9 @@ use rustc_span::source_map::Span; use syntax::ast::Mutability; use super::eval_context::{LocalState, StackPopCleanup}; -use super::{Frame, Immediate, LocalValue, MemPlace, Memory, Operand, Place, ScalarMaybeUndef}; +use super::{ + Frame, Immediate, LocalValue, MemPlace, MemPlaceMeta, Memory, Operand, Place, ScalarMaybeUndef, +}; use crate::const_eval::CompileTimeInterpreter; #[derive(Default)] @@ -205,6 +207,14 @@ impl_snapshot_for!( } ); +impl_snapshot_for!( + enum MemPlaceMeta { + Unsized(s), + None, + Poison, + } +); + impl_snapshot_for!(struct MemPlace { ptr, meta, diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 786909731531f..7a7f431402075 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -16,7 +16,7 @@ use rustc_span::symbol::{sym, Symbol}; use std::hash::Hash; use super::{ - CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Scalar, + CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, ValueVisitor, }; @@ -246,13 +246,13 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M fn check_wide_ptr_meta( &mut self, - meta: Option>, + meta: MemPlaceMeta, pointee: TyLayout<'tcx>, ) -> InterpResult<'tcx> { let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); match tail.kind { ty::Dynamic(..) => { - let vtable = meta.unwrap(); + let vtable = meta.unwrap_unsized(); try_validation!( self.ecx.memory.check_ptr_access( vtable, @@ -276,7 +276,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M } ty::Slice(..) | ty::Str => { let _len = try_validation!( - meta.unwrap().to_machine_usize(self.ecx), + meta.unwrap_unsized().to_machine_usize(self.ecx), "non-integer slice length in wide pointer", self.path ); @@ -572,8 +572,11 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> match op.layout.ty.kind { ty::Str => { let mplace = op.assert_mem_place(self.ecx); // strings are never immediate - try_validation!(self.ecx.read_str(mplace), - "uninitialized or non-UTF-8 data in str", self.path); + try_validation!( + self.ecx.read_str(mplace), + "uninitialized or non-UTF-8 data in str", + self.path + ); } ty::Array(tys, ..) | ty::Slice(tys) if { From 23b0c470244e612206486bb51f687ef4f6b6e117 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 27 Dec 2019 00:52:12 +0100 Subject: [PATCH 06/13] Ensure we don't accidentally turn non-zsts into zsts --- src/librustc_mir/const_eval/eval_queries.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index b0add10dcac43..9fbb6e1a39d90 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -125,6 +125,7 @@ pub(super) fn op_to_const<'tcx>( } Scalar::Raw { data, .. } => { assert_eq!(data, mplace.layout.align.abi.bytes().into()); + assert!(mplace.layout.is_zst()); ConstValue::Scalar(Scalar::zst()) } }; From a1990db7c68ead195d1ddf4b245e3c0e6f721fbc Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 27 Dec 2019 00:58:48 +0100 Subject: [PATCH 07/13] Remove a bunch of dead functions and make some functions private --- src/librustc_mir/interpret/operand.rs | 24 ------------------------ src/librustc_mir/interpret/place.rs | 16 +++------------- 2 files changed, 3 insertions(+), 37 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 00aecf74c7d3d..ddd9776e89383 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -153,30 +153,6 @@ pub enum Operand { Indirect(MemPlace), } -impl Operand { - #[inline] - pub fn assert_mem_place(self) -> MemPlace - where - Tag: ::std::fmt::Debug, - { - match self { - Operand::Indirect(mplace) => mplace, - _ => bug!("assert_mem_place: expected Operand::Indirect, got {:?}", self), - } - } - - #[inline] - pub fn assert_immediate(self) -> Immediate - where - Tag: ::std::fmt::Debug, - { - match self { - Operand::Immediate(imm) => imm, - _ => bug!("assert_immediate: expected Operand::Immediate, got {:?}", self), - } - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct OpTy<'tcx, Tag = ()> { op: Operand, // Keep this private; it helps enforce invariants. diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 6d848092defe5..f5e8d052b21f1 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -131,13 +131,13 @@ impl MemPlace { } #[inline(always)] - pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self { + fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self { MemPlace { ptr, align, meta: MemPlaceMeta::None } } /// Produces a Place that will error if attempted to be read from or written to #[inline(always)] - pub fn null(cx: &impl HasDataLayout) -> Self { + fn null(cx: &impl HasDataLayout) -> Self { Self::from_scalar_ptr(Scalar::ptr_null(cx), Align::from_bytes(1).unwrap()) } @@ -263,20 +263,10 @@ impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { impl Place { /// Produces a Place that will error if attempted to be read from or written to #[inline(always)] - pub fn null(cx: &impl HasDataLayout) -> Self { + fn null(cx: &impl HasDataLayout) -> Self { Place::Ptr(MemPlace::null(cx)) } - #[inline(always)] - pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self { - Place::Ptr(MemPlace::from_scalar_ptr(ptr, align)) - } - - #[inline(always)] - pub fn from_ptr(ptr: Pointer, align: Align) -> Self { - Place::Ptr(MemPlace::from_ptr(ptr, align)) - } - #[inline] pub fn assert_mem_place(self) -> MemPlace { match self { From f7f59522b6354d66cf1f08ff0b665d3699acd98c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 27 Dec 2019 01:00:05 +0100 Subject: [PATCH 08/13] Add warning label to `try_as_mplace` --- src/librustc_mir/interpret/place.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index f5e8d052b21f1..1f7db45ccff56 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -241,6 +241,8 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { // These are defined here because they produce a place. impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { #[inline(always)] + /// Note: do not call `as_ref` on the resulting place. This function should only be used to + /// read from the resulting mplace, not to get its address back. pub fn try_as_mplace( self, cx: &impl HasDataLayout, @@ -255,6 +257,8 @@ impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { } #[inline(always)] + /// Note: do not call `as_ref` on the resulting place. This function should only be used to + /// read from the resulting mplace, not to get its address back. pub fn assert_mem_place(self, cx: &impl HasDataLayout) -> MPlaceTy<'tcx, Tag> { self.try_as_mplace(cx).unwrap() } From 29c372bf8b612dd9e23eb2503a1f1167e2f2f47c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 7 Jan 2020 15:51:43 +0100 Subject: [PATCH 09/13] Add more documentation --- src/librustc_mir/const_eval/eval_queries.rs | 7 ++++++- src/librustc_mir/interpret/place.rs | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 9fbb6e1a39d90..d2a0798249ad9 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -124,7 +124,12 @@ pub(super) fn op_to_const<'tcx>( ConstValue::ByRef { alloc, offset: ptr.offset } } Scalar::Raw { data, .. } => { - assert_eq!(data, mplace.layout.align.abi.bytes().into()); + assert_eq!( + data, + mplace.layout.align.abi.bytes().into(), + "this MPlaceTy must come from `try_as_mplace` being used on a zst, so we know what + value this integer address must have", + ); assert!(mplace.layout.is_zst()); ConstValue::Scalar(Scalar::zst()) } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 1f7db45ccff56..69563c5a08de1 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -21,7 +21,9 @@ use super::{ }; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)] +/// Information required for the sound usage of a `MemPlace`. pub enum MemPlaceMeta { + /// The unsized payload (e.g. length for slices or vtable pointer for trait objects). Unsized(Scalar), /// `Sized` types or unsized `extern type` None, From d0b24e5ee292cc785401c880f21b690f5f3fa1d6 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 7 Jan 2020 15:59:14 +0100 Subject: [PATCH 10/13] Actually use the poison value --- src/librustc_mir/interpret/place.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 69563c5a08de1..6428caa8fb0ed 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -180,13 +180,9 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { /// Produces a MemPlace that works for ZST but nothing else #[inline] pub fn dangling(layout: TyLayout<'tcx>, cx: &impl HasDataLayout) -> Self { - MPlaceTy { - mplace: MemPlace::from_scalar_ptr( - Scalar::from_uint(layout.align.abi.bytes(), cx.pointer_size()), - layout.align.abi, - ), - layout, - } + let align = layout.align.abi; + let ptr = Scalar::from_uint(align.bytes(), cx.pointer_size()); + MPlaceTy { mplace: MemPlace { ptr, align, meta: MemPlaceMeta::Poison }, layout } } /// Replace ptr tag, maintain vtable tag (if any) From e632940a41fe6d65bd677da85d87046dc5da5022 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 9 Jan 2020 10:56:05 +0100 Subject: [PATCH 11/13] Update src/librustc_mir/interpret/place.rs Co-Authored-By: Ralf Jung --- src/librustc_mir/interpret/place.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 6428caa8fb0ed..87bb4c04b73ac 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -182,6 +182,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { pub fn dangling(layout: TyLayout<'tcx>, cx: &impl HasDataLayout) -> Self { let align = layout.align.abi; let ptr = Scalar::from_uint(align.bytes(), cx.pointer_size()); + // `Poison` this to make sure that the pointer value `ptr` is never observable by the program. MPlaceTy { mplace: MemPlace { ptr, align, meta: MemPlaceMeta::Poison }, layout } } From a4fa5bb6a0396b54a4519a20cd61c321905b5ac2 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 9 Jan 2020 12:02:44 +0100 Subject: [PATCH 12/13] Rename `Unsized` to `Meta` --- src/librustc_mir/interpret/eval_context.rs | 6 ++--- src/librustc_mir/interpret/intern.rs | 4 ++-- src/librustc_mir/interpret/place.rs | 28 +++++++++++----------- src/librustc_mir/interpret/snapshot.rs | 2 +- src/librustc_mir/interpret/validity.rs | 4 ++-- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index c5c2a6769e44a..864f4f9487c88 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -465,13 +465,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(Some((size, align))) } ty::Dynamic(..) => { - let vtable = metadata.unwrap_unsized(); + let vtable = metadata.unwrap_meta(); // Read size and align from vtable (already checks size). Ok(Some(self.read_size_and_align_from_vtable(vtable)?)) } ty::Slice(_) | ty::Str => { - let len = metadata.unwrap_unsized().to_machine_usize(self)?; + let len = metadata.unwrap_meta().to_machine_usize(self)?; let elem = layout.field(self, 0)?; // Make sure the slice is not too big. @@ -817,7 +817,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { " by align({}){} ref:", mplace.align.bytes(), match mplace.meta { - MemPlaceMeta::Unsized(meta) => format!(" meta({:?})", meta), + MemPlaceMeta::Meta(meta) => format!(" meta({:?})", meta), MemPlaceMeta::Poison | MemPlaceMeta::None => String::new(), } ) diff --git a/src/librustc_mir/interpret/intern.rs b/src/librustc_mir/interpret/intern.rs index 56e489d0bd590..9b3a2fa36f794 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/src/librustc_mir/interpret/intern.rs @@ -193,7 +193,7 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx { // Validation has already errored on an invalid vtable pointer so we can safely not // do anything if this is not a real pointer. - if let Scalar::Ptr(vtable) = mplace.meta.unwrap_unsized() { + if let Scalar::Ptr(vtable) = mplace.meta.unwrap_meta() { // Explicitly choose `Immutable` here, since vtables are immutable, even // if the reference of the fat pointer is mutable. self.intern_shallow(vtable.alloc_id, Mutability::Not, None)?; @@ -227,7 +227,7 @@ impl<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx ty::Array(_, n) if n.eval_usize(self.ecx.tcx.tcx, self.ecx.param_env) == 0 => {} ty::Slice(_) - if mplace.meta.unwrap_unsized().to_machine_usize(self.ecx)? == 0 => {} + if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)? == 0 => {} _ => bug!("const qualif failed to prevent mutable references"), }, } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 87bb4c04b73ac..890627a54543a 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -24,7 +24,7 @@ use super::{ /// Information required for the sound usage of a `MemPlace`. pub enum MemPlaceMeta { /// The unsized payload (e.g. length for slices or vtable pointer for trait objects). - Unsized(Scalar), + Meta(Scalar), /// `Sized` types or unsized `extern type` None, /// The address of this place may not be taken. This protects the `MemPlace` from coming from @@ -35,17 +35,17 @@ pub enum MemPlaceMeta { } impl MemPlaceMeta { - pub fn unwrap_unsized(self) -> Scalar { + pub fn unwrap_meta(self) -> Scalar { match self { - Self::Unsized(s) => s, + Self::Meta(s) => s, Self::None | Self::Poison => { bug!("expected wide pointer extra data (e.g. slice length or trait object vtable)") } } } - fn is_unsized(self) -> bool { + fn has_meta(self) -> bool { match self { - Self::Unsized(_) => true, + Self::Meta(_) => true, Self::None | Self::Poison => false, } } @@ -54,7 +54,7 @@ impl MemPlaceMeta { impl MemPlaceMeta { pub fn erase_tag(self) -> MemPlaceMeta<()> { match self { - Self::Unsized(s) => MemPlaceMeta::Unsized(s.erase_tag()), + Self::Meta(s) => MemPlaceMeta::Meta(s.erase_tag()), Self::None => MemPlaceMeta::None, Self::Poison => MemPlaceMeta::Poison, } @@ -154,7 +154,7 @@ impl MemPlace { pub fn to_ref(self) -> Immediate { match self.meta { MemPlaceMeta::None => Immediate::Scalar(self.ptr.into()), - MemPlaceMeta::Unsized(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()), + MemPlaceMeta::Meta(meta) => Immediate::ScalarPair(self.ptr.into(), meta.into()), MemPlaceMeta::Poison => bug!( "MPlaceTy::dangling may never be used to produce a \ place that will have the address of its pointee taken" @@ -214,7 +214,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { // We need to consult `meta` metadata match self.layout.ty.kind { ty::Slice(..) | ty::Str => { - return self.mplace.meta.unwrap_unsized().to_machine_usize(cx); + return self.mplace.meta.unwrap_meta().to_machine_usize(cx); } _ => bug!("len not supported on unsized type {:?}", self.layout.ty), } @@ -231,7 +231,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { #[inline] pub(super) fn vtable(self) -> Scalar { match self.layout.ty.kind { - ty::Dynamic(..) => self.mplace.meta.unwrap_unsized(), + ty::Dynamic(..) => self.mplace.meta.unwrap_meta(), _ => bug!("vtable not supported on type {:?}", self.layout.ty), } } @@ -312,7 +312,7 @@ where let (ptr, meta) = match *val { Immediate::Scalar(ptr) => (ptr.not_undef()?, MemPlaceMeta::None), Immediate::ScalarPair(ptr, meta) => { - (ptr.not_undef()?, MemPlaceMeta::Unsized(meta.not_undef()?)) + (ptr.not_undef()?, MemPlaceMeta::Meta(meta.not_undef()?)) } }; @@ -354,7 +354,7 @@ where ) -> InterpResult<'tcx, Option>> { let size = size.unwrap_or_else(|| { assert!(!place.layout.is_unsized()); - assert!(!place.meta.is_unsized()); + assert!(!place.meta.has_meta()); place.layout.size }); self.memory.check_ptr_access(place.ptr, size, place.align) @@ -505,7 +505,7 @@ where ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(inner, inner_len)), ty::Slice(..) => { let len = Scalar::from_uint(inner_len, self.pointer_size()); - (MemPlaceMeta::Unsized(len), base.layout.ty) + (MemPlaceMeta::Meta(len), base.layout.ty) } _ => bug!("cannot subslice non-array type: `{:?}`", base.layout.ty), }; @@ -519,7 +519,7 @@ where variant: VariantIdx, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // Downcasts only change the layout - assert!(!base.meta.is_unsized()); + assert!(!base.meta.has_meta()); Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base }) } @@ -1081,7 +1081,7 @@ where let mplace = MemPlace { ptr: ptr.into(), align: Align::from_bytes(1).unwrap(), - meta: MemPlaceMeta::Unsized(meta), + meta: MemPlaceMeta::Meta(meta), }; let layout = self.layout_of(self.tcx.mk_static_str()).unwrap(); diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index 120baaf3be68a..a8e67c8f208a9 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -209,7 +209,7 @@ impl_snapshot_for!( impl_snapshot_for!( enum MemPlaceMeta { - Unsized(s), + Meta(s), None, Poison, } diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 7a7f431402075..12e8cb6071d92 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -252,7 +252,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); match tail.kind { ty::Dynamic(..) => { - let vtable = meta.unwrap_unsized(); + let vtable = meta.unwrap_meta(); try_validation!( self.ecx.memory.check_ptr_access( vtable, @@ -276,7 +276,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M } ty::Slice(..) | ty::Str => { let _len = try_validation!( - meta.unwrap_unsized().to_machine_usize(self.ecx), + meta.unwrap_meta().to_machine_usize(self.ecx), "non-integer slice length in wide pointer", self.path ); From c5c4fa8e7633c28464e3b27a57f2f175cc6700fd Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 9 Jan 2020 12:03:37 +0100 Subject: [PATCH 13/13] Switch assertion order to be more helpful to ppl that encounter them --- src/librustc_mir/const_eval/eval_queries.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index d2a0798249ad9..53f3b539bdaa0 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -124,13 +124,13 @@ pub(super) fn op_to_const<'tcx>( ConstValue::ByRef { alloc, offset: ptr.offset } } Scalar::Raw { data, .. } => { + assert!(mplace.layout.is_zst()); assert_eq!( data, mplace.layout.align.abi.bytes().into(), "this MPlaceTy must come from `try_as_mplace` being used on a zst, so we know what value this integer address must have", ); - assert!(mplace.layout.is_zst()); ConstValue::Scalar(Scalar::zst()) } };