diff options
| author | bors <bors@rust-lang.org> | 2022-06-06 13:28:58 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-06-06 13:28:58 +0000 |
| commit | 9d20fd109809f20c049d6895a5be27a1fbd39daa (patch) | |
| tree | f1e763afe425ff467dae3936729d1dfdaec41b6f /compiler/rustc_const_eval/src | |
| parent | 79b6bad406155cad4481150fc5dfa0da5394e3b6 (diff) | |
| parent | d208f8003937e4de4ff40076231a4a23f32c6ec7 (diff) | |
| download | rust-9d20fd109809f20c049d6895a5be27a1fbd39daa.tar.gz rust-9d20fd109809f20c049d6895a5be27a1fbd39daa.zip | |
Auto merge of #97684 - RalfJung:better-provenance-control, r=oli-obk
interpret: better control over whether we read data with provenance The resolution in https://github.com/rust-lang/unsafe-code-guidelines/issues/286 seems to be that when we load data at integer type, we implicitly strip provenance. So let's implement that in Miri at least for scalar loads. This makes use of the fact that `Scalar` layouts distinguish pointer-sized integers and pointers -- so I was expecting some wild bugs where layouts set this incorrectly, but so far that does not seem to happen. This does not entirely implement the solution to https://github.com/rust-lang/unsafe-code-guidelines/issues/286; we still do the wrong thing for integers in larger types: we will `copy_op` them and then do validation, and validation will complain about the provenance. To fix that we need mutating validation; validation needs to strip the provenance rather than complaining about it. This is a larger undertaking (but will also help resolve https://github.com/rust-lang/miri/issues/845 since we can reset padding to `Uninit`). The reason this is useful is that we can now implement `addr` as a `transmute` from a pointer to an integer, and actually get the desired behavior of stripping provenance without exposing it!
Diffstat (limited to 'compiler/rustc_const_eval/src')
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/memory.rs | 23 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/operand.rs | 21 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/traits.rs | 19 |
3 files changed, 45 insertions, 18 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 9c032c55fe5..f3f3c5bf946 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -908,11 +908,15 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> { } impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> { - pub fn read_scalar(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { + pub fn read_scalar( + &self, + range: AllocRange, + read_provenance: bool, + ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { let range = self.range.subrange(range); let res = self .alloc - .read_scalar(&self.tcx, range) + .read_scalar(&self.tcx, range, read_provenance) .map_err(|e| e.to_interp_error(self.alloc_id))?; debug!( "read_scalar in {} at {:#x}, size {}: {:?}", @@ -924,8 +928,19 @@ impl<'tcx, 'a, Tag: Provenance, Extra> AllocRef<'a, 'tcx, Tag, Extra> { Ok(res) } - pub fn read_ptr_sized(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { - self.read_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size)) + pub fn read_integer( + &self, + offset: Size, + size: Size, + ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { + self.read_scalar(alloc_range(offset, size), /*read_provenance*/ false) + } + + pub fn read_pointer(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { + self.read_scalar( + alloc_range(offset, self.tcx.data_layout().pointer_size), + /*read_provenance*/ true, + ) } pub fn check_bytes( diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index f5e1ee4e233..6338e08380f 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -15,8 +15,8 @@ use rustc_target::abi::{VariantIdx, Variants}; use super::{ alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, GlobalId, - InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, Provenance, - Scalar, ScalarMaybeUninit, + InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, + PointerArithmetic, Provenance, Scalar, ScalarMaybeUninit, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -284,11 +284,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Abi::Scalar(s) if force => Some(s.primitive()), _ => None, }; - if let Some(_s) = scalar_layout { + let read_provenance = |s: abi::Primitive, size| { + // Should be just `s.is_ptr()`, but we support a Miri flag that accepts more + // questionable ptr-int transmutes. + let number_may_have_provenance = !M::enforce_number_no_provenance(self); + s.is_ptr() || (number_may_have_provenance && size == self.pointer_size()) + }; + if let Some(s) = scalar_layout { //FIXME(#96185): let size = s.size(self); //FIXME(#96185): assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size"); let size = mplace.layout.size; //FIXME(#96185): remove this line - let scalar = alloc.read_scalar(alloc_range(Size::ZERO, size))?; + let scalar = + alloc.read_scalar(alloc_range(Size::ZERO, size), read_provenance(s, size))?; return Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout })); } let scalar_pair_layout = match mplace.layout.abi { @@ -306,8 +313,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let (a_size, b_size) = (a.size(self), b.size(self)); let b_offset = a_size.align_to(b.align(self).abi); assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields - let a_val = alloc.read_scalar(alloc_range(Size::ZERO, a_size))?; - let b_val = alloc.read_scalar(alloc_range(b_offset, b_size))?; + let a_val = + alloc.read_scalar(alloc_range(Size::ZERO, a_size), read_provenance(a, a_size))?; + let b_val = + alloc.read_scalar(alloc_range(b_offset, b_size), read_provenance(b, b_size))?; return Ok(Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout, diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index c4d1074e437..9c48f3e8337 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -50,7 +50,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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_ptr_sized(Size::ZERO)?.check_init()?)?; + let fn_ptr = self.scalar_to_ptr(vtable_slot.read_pointer(Size::ZERO)?.check_init()?)?; self.get_ptr_fn(fn_ptr) } @@ -69,9 +69,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { )? .expect("cannot be a ZST"); let drop_fn = vtable - .read_ptr_sized( - pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_DROPINPLACE).unwrap(), - )? + .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. @@ -104,12 +102,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { )? .expect("cannot be a ZST"); let size = vtable - .read_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_SIZE).unwrap())? + .read_integer( + 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_ptr_sized(pointer_size * u64::try_from(COMMON_VTABLE_ENTRIES_ALIGN).unwrap())? + .read_integer( + 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)))?; @@ -132,8 +136,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .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_ptr_sized(Size::ZERO)?.check_init()?)?; + let new_vtable = self.scalar_to_ptr(new_vtable.read_pointer(Size::ZERO)?.check_init()?)?; Ok(new_vtable) } |
