From 6f407d67b8ae387f763fa8e8dbc269b16a996ce3 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Mon, 13 Feb 2023 22:30:53 -0500 Subject: [PATCH 1/7] Allow non-`Box` allocations in preparation for aligned const allocations for miri. Credit to emarteca for the code. --- .../rustc_const_eval/src/interpret/machine.rs | 10 ++- .../rustc_const_eval/src/interpret/memory.rs | 42 +++++---- .../rustc_const_eval/src/interpret/place.rs | 4 +- .../src/mir/interpret/allocation.rs | 88 +++++++++++++++---- .../rustc_middle/src/mir/interpret/mod.rs | 2 +- compiler/rustc_middle/src/mir/pretty.rs | 22 ++--- 6 files changed, 120 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 450488315ef01..3a4df2da1ed51 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -16,7 +16,7 @@ use rustc_target::spec::abi::Abi as CallAbi; use crate::const_eval::CheckAlignment; use super::{ - AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult, + AllocId, AllocRange, Allocation, AllocBytes, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind, }; @@ -105,10 +105,13 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Extra data stored in every allocation. type AllocExtra: Debug + Clone + 'static; + /// Type for the bytes of the allocation. + type Bytes: AllocBytes + 'static; + /// Memory's allocation map type MemoryMap: AllocMap< AllocId, - (MemoryKind, Allocation), + (MemoryKind, Allocation), > + Default + Clone; @@ -338,7 +341,7 @@ pub trait Machine<'mir, 'tcx>: Sized { id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> InterpResult<'tcx, Cow<'b, Allocation>>; + ) -> InterpResult<'tcx, Cow<'b, Allocation>>; fn eval_inline_asm( _ecx: &mut InterpCx<'mir, 'tcx, Self>, @@ -459,6 +462,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { type AllocExtra = (); type FrameExtra = (); + type Bytes = Box<[u8]>; #[inline(always)] fn use_addr_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index f4e03ad8c593d..a817211e745b7 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -21,8 +21,9 @@ use rustc_target::abi::{Align, HasDataLayout, Size}; use crate::const_eval::CheckAlignment; use super::{ - alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc, InterpCx, - InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, Scalar, + alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, + GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, + Scalar, }; #[derive(Debug, PartialEq, Copy, Clone)] @@ -114,16 +115,16 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// A reference to some allocation that was already bounds-checked for the given region /// and had the on-access machine hooks run. #[derive(Copy, Clone)] -pub struct AllocRef<'a, 'tcx, Prov: Provenance, Extra> { - alloc: &'a Allocation, +pub struct AllocRef<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes = Box<[u8]>> { + alloc: &'a Allocation, range: AllocRange, tcx: TyCtxt<'tcx>, alloc_id: AllocId, } /// A reference to some allocation that was already bounds-checked for the given region /// and had the on-access machine hooks run. -pub struct AllocRefMut<'a, 'tcx, Prov: Provenance, Extra> { - alloc: &'a mut Allocation, +pub struct AllocRefMut<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes = Box<[u8]>> { + alloc: &'a mut Allocation, range: AllocRange, tcx: TyCtxt<'tcx>, alloc_id: AllocId, @@ -483,7 +484,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { &self, id: AllocId, is_write: bool, - ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { + ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { let (alloc, def_id) = match self.tcx.try_get_global_alloc(id) { Some(GlobalAlloc::Memory(mem)) => { // Memory of a constant or promoted or anonymous memory referenced by a static. @@ -526,6 +527,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) } + /// Get the base address for the bytes in an `Allocation` specified by the + /// `AllocID` passed in; error if no such allocation exists. + /// + /// It is up to the caller to take sufficient care when using this address: + /// there could be provenance or uninit memory in there, and other memory + /// accesses could invalidate the exposed pointer. + pub fn alloc_base_addr(&self, id: AllocId) -> InterpResult<'tcx, *const ()> { + let alloc = self.get_alloc_raw(id)?; + Ok(alloc.base_addr()) + } + /// Gives raw access to the `Allocation`, without bounds or alignment checks. /// The caller is responsible for calling the access hooks! /// @@ -533,7 +545,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn get_alloc_raw( &self, id: AllocId, - ) -> InterpResult<'tcx, &Allocation> { + ) -> InterpResult<'tcx, &Allocation> { // The error type of the inner closure here is somewhat funny. We have two // ways of "erroring": An actual error, or because we got a reference from // `get_global_alloc` that we can actually use directly without inserting anything anywhere. @@ -569,7 +581,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ptr: Pointer>, size: Size, align: Align, - ) -> InterpResult<'tcx, Option>> { + ) -> InterpResult<'tcx, Option>> { let ptr_and_alloc = self.check_and_deref_ptr( ptr, size, @@ -612,7 +624,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn get_alloc_raw_mut( &mut self, id: AllocId, - ) -> InterpResult<'tcx, (&mut Allocation, &mut M)> { + ) -> InterpResult<'tcx, (&mut Allocation, &mut M)> { // We have "NLL problem case #3" here, which cannot be worked around without loss of // efficiency even for the common case where the key is in the map. // @@ -641,7 +653,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ptr: Pointer>, size: Size, align: Align, - ) -> InterpResult<'tcx, Option>> { + ) -> InterpResult<'tcx, Option>> { let parts = self.get_ptr_access(ptr, size, align)?; if let Some((alloc_id, offset, prov)) = parts { let tcx = *self.tcx; @@ -840,11 +852,11 @@ pub struct DumpAllocs<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, 'mir, 'tcx, M> { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Cannot be a closure because it is generic in `Prov`, `Extra`. - fn write_allocation_track_relocs<'tcx, Prov: Provenance, Extra>( + fn write_allocation_track_relocs<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( fmt: &mut std::fmt::Formatter<'_>, tcx: TyCtxt<'tcx>, allocs_to_print: &mut VecDeque, - alloc: &Allocation, + alloc: &Allocation, ) -> std::fmt::Result { for alloc_id in alloc.provenance().provenances().filter_map(|prov| prov.get_alloc_id()) { @@ -912,7 +924,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, } /// Reading and writing. -impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> { +impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRefMut<'a, 'tcx, Prov, Extra, Bytes> { /// `range` is relative to this allocation reference, not the base of the allocation. pub fn write_scalar(&mut self, range: AllocRange, val: Scalar) -> InterpResult<'tcx> { let range = self.range.subrange(range); @@ -937,7 +949,7 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRefMut<'a, 'tcx, Prov, Extra> { } } -impl<'tcx, 'a, Prov: Provenance, Extra> AllocRef<'a, 'tcx, Prov, Extra> { +impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Prov, Extra, Bytes> { /// `range` is relative to this allocation reference, not the base of the allocation. pub fn read_scalar( &self, diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 88485c06ed86c..ad2d543854941 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -340,7 +340,7 @@ where pub(super) fn get_place_alloc( &self, place: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Option>> { + ) -> InterpResult<'tcx, Option>> { assert!(place.layout.is_sized()); assert!(!place.meta.has_meta()); let size = place.layout.size; @@ -351,7 +351,7 @@ where pub(super) fn get_place_alloc_mut( &mut self, place: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Option>> { + ) -> InterpResult<'tcx, Option>> { assert!(place.layout.is_sized()); assert!(!place.meta.has_meta()); let size = place.layout.size; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 221105ac48f79..2ddfdbbc25acf 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -8,7 +8,8 @@ mod tests; use std::borrow::Cow; use std::fmt; use std::hash; -use std::ops::Range; +use std::hash::Hash; +use std::ops::{Deref, DerefMut, Range}; use std::ptr; use either::{Left, Right}; @@ -29,6 +30,54 @@ use provenance_map::*; pub use init_mask::{InitChunk, InitChunkIter}; +/// Functionality required for the bytes of an `Allocation`. +pub trait AllocBytes: + Clone + + fmt::Debug + + Eq + + PartialEq + + Hash + + Deref + + DerefMut +{ + /// Adjust the bytes to the specified alignment -- by default, this is a no-op. + fn adjust_to_align(self, _align: Align) -> Self; + + /// Create an `AllocBytes` from a slice of `u8`. + fn from_bytes<'a>(slice: impl Into>, _align: Align) -> Self; + + /// Create a zeroed `AllocBytes` of the specified size and alignment; + /// call the callback error handler if there is an error in allocating the memory. + fn zeroed<'tcx, F: Fn() -> InterpError<'tcx>>( + size: Size, + _align: Align, + handle_alloc_fail: F, + ) -> Result>; +} + +// Default `bytes` for `Allocation` is a `Box<[u8]>`. +impl AllocBytes for Box<[u8]> { + fn adjust_to_align(self, _align: Align) -> Self { + self + } + + fn from_bytes<'a>(slice: impl Into>, _align: Align) -> Self { + Box::<[u8]>::from(slice.into()) + } + + fn zeroed<'tcx, F: Fn() -> InterpError<'tcx>>( + size: Size, + _align: Align, + handle_alloc_fail: F, + ) -> Result> { + let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()) + .map_err(|_| handle_alloc_fail())?; + // SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]> + let bytes = unsafe { bytes.assume_init() }; + Ok(bytes) + } +} + /// This type represents an Allocation in the Miri/CTFE core engine. /// /// Its public API is rather low-level, working directly with allocation offsets and a custom error @@ -38,10 +87,10 @@ pub use init_mask::{InitChunk, InitChunkIter}; // hashed. (see the `Hash` impl below for more details), so the impl is not derived. #[derive(Clone, Eq, PartialEq, TyEncodable, TyDecodable)] #[derive(HashStable)] -pub struct Allocation { +pub struct Allocation> { /// The actual bytes of the allocation. /// Note that the bytes of a pointer represent the offset of the pointer. - bytes: Box<[u8]>, + bytes: Bytes, /// Maps from byte addresses to extra provenance data for each pointer. /// Only the first byte of a pointer is inserted into the map; i.e., /// every entry in this map applies to `pointer_size` consecutive bytes starting @@ -220,14 +269,14 @@ impl AllocRange { } // The constructors are all without extra; the extra gets added by a machine hook later. -impl Allocation { +impl Allocation { /// Creates an allocation initialized by the given bytes pub fn from_bytes<'a>( slice: impl Into>, align: Align, mutability: Mutability, ) -> Self { - let bytes = Box::<[u8]>::from(slice.into()); + let bytes = Bytes::from_bytes(slice, align); let size = Size::from_bytes(bytes.len()); Self { bytes, @@ -248,7 +297,7 @@ impl Allocation { /// /// If `panic_on_fail` is true, this will never return `Err`. pub fn uninit<'tcx>(size: Size, align: Align, panic_on_fail: bool) -> InterpResult<'tcx, Self> { - let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()).map_err(|_| { + let handle_alloc_fail = || -> InterpError<'tcx> { // This results in an error that can happen non-deterministically, since the memory // available to the compiler can change between runs. Normally queries are always // deterministic. However, we can be non-deterministic here because all uses of const @@ -261,9 +310,10 @@ impl Allocation { tcx.sess.delay_span_bug(DUMMY_SP, "exhausted memory during interpretation") }); InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted) - })?; - // SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]> - let bytes = unsafe { bytes.assume_init() }; + }; + + let bytes = Bytes::zeroed(size, align, handle_alloc_fail)?; + Ok(Allocation { bytes, provenance: ProvenanceMap::new(), @@ -275,7 +325,7 @@ impl Allocation { } } -impl Allocation { +impl Allocation { /// Adjust allocation from the ones in tcx to a custom Machine instance /// with a different Provenance and Extra type. pub fn adjust_from_tcx( @@ -283,9 +333,11 @@ impl Allocation { cx: &impl HasDataLayout, extra: Extra, mut adjust_ptr: impl FnMut(Pointer) -> Result, Err>, - ) -> Result, Err> { - // Compute new pointer provenance, which also adjusts the bytes. - let mut bytes = self.bytes; + ) -> Result, Err> { + // Compute new pointer provenance, which also adjusts the bytes, and realign the pointer if + // necessary. + let mut bytes = self.bytes.adjust_to_align(self.align); + let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len()); let ptr_size = cx.data_layout().pointer_size.bytes_usize(); let endian = cx.data_layout().endian; @@ -311,7 +363,7 @@ impl Allocation { } /// Raw accessors. Provide access to otherwise private bytes. -impl Allocation { +impl Allocation { pub fn len(&self) -> usize { self.bytes.len() } @@ -340,7 +392,11 @@ impl Allocation { } /// Byte accessors. -impl Allocation { +impl Allocation { + pub fn base_addr(&self) -> *const u8 { + self.bytes.as_ptr() + } + /// This is the entirely abstraction-violating way to just grab the raw bytes without /// caring about provenance or initialization. /// @@ -412,7 +468,7 @@ impl Allocation { } /// Reading and writing. -impl Allocation { +impl Allocation { /// Sets the init bit for the given range. fn mark_init(&mut self, range: AllocRange, is_init: bool) { if range.size.bytes() == 0 { diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index b0975616b6151..4329bbf803076 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -127,7 +127,7 @@ pub use self::error::{ pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar}; pub use self::allocation::{ - alloc_range, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, InitChunk, + alloc_range, AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, InitChunk, InitChunkIter, }; diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 16daf63b82d9f..d8829e3e782c5 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -12,8 +12,8 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_index::vec::Idx; use rustc_middle::mir::interpret::{ - alloc_range, read_target_uint, AllocId, Allocation, ConstAllocation, ConstValue, GlobalAlloc, - Pointer, Provenance, + alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, ConstAllocation, ConstValue, + GlobalAlloc, Pointer, Provenance, }; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; @@ -787,21 +787,21 @@ pub fn write_allocations<'tcx>( /// After the hex dump, an ascii dump follows, replacing all unprintable characters (control /// characters or characters whose value is larger than 127) with a `.` /// This also prints provenance adequately. -pub fn display_allocation<'a, 'tcx, Prov: Provenance, Extra>( +pub fn display_allocation<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( tcx: TyCtxt<'tcx>, - alloc: &'a Allocation, -) -> RenderAllocation<'a, 'tcx, Prov, Extra> { + alloc: &'a Allocation, +) -> RenderAllocation<'a, 'tcx, Prov, Extra, Bytes> { RenderAllocation { tcx, alloc } } #[doc(hidden)] -pub struct RenderAllocation<'a, 'tcx, Prov: Provenance, Extra> { +pub struct RenderAllocation<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> { tcx: TyCtxt<'tcx>, - alloc: &'a Allocation, + alloc: &'a Allocation, } -impl<'a, 'tcx, Prov: Provenance, Extra> std::fmt::Display - for RenderAllocation<'a, 'tcx, Prov, Extra> +impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> std::fmt::Display + for RenderAllocation<'a, 'tcx, Prov, Extra, Bytes> { fn fmt(&self, w: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let RenderAllocation { tcx, alloc } = *self; @@ -845,9 +845,9 @@ fn write_allocation_newline( /// The `prefix` argument allows callers to add an arbitrary prefix before each line (even if there /// is only one line). Note that your prefix should contain a trailing space as the lines are /// printed directly after it. -fn write_allocation_bytes<'tcx, Prov: Provenance, Extra>( +fn write_allocation_bytes<'tcx, Prov: Provenance, Extra, Bytes: AllocBytes>( tcx: TyCtxt<'tcx>, - alloc: &Allocation, + alloc: &Allocation, w: &mut dyn std::fmt::Write, prefix: &str, ) -> std::fmt::Result { From b2455dc91ce7d43ea883ea5d2ec8adb6e90fc4d4 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Mon, 13 Feb 2023 23:16:56 -0500 Subject: [PATCH 2/7] Add mentioned from_raw_bytes constructor --- .../src/mir/interpret/allocation.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 2ddfdbbc25acf..974db3f440224 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -270,6 +270,23 @@ impl AllocRange { // The constructors are all without extra; the extra gets added by a machine hook later. impl Allocation { + /// Creates an allocation from an existing `Bytes` value - this is needed for miri FFI support + pub fn from_raw_bytes<'a>( + bytes: Bytes, + align: Align, + mutability: Mutability, + ) -> Self { + let size = Size::from_bytes(bytes.len()); + Self { + bytes, + provenance: ProvenanceMap::new(), + init_mask: InitMask::new(size, true), + align, + mutability, + extra: (), + } + } + /// Creates an allocation initialized by the given bytes pub fn from_bytes<'a>( slice: impl Into>, From f1f40ac05c9d23b6a03dcd1d233f28f4794c0f07 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Mon, 13 Feb 2023 23:19:34 -0500 Subject: [PATCH 3/7] Fix alloc_base_addr type --- compiler/rustc_const_eval/src/interpret/memory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index a817211e745b7..ead4ee7b5f791 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -533,7 +533,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// It is up to the caller to take sufficient care when using this address: /// there could be provenance or uninit memory in there, and other memory /// accesses could invalidate the exposed pointer. - pub fn alloc_base_addr(&self, id: AllocId) -> InterpResult<'tcx, *const ()> { + pub fn alloc_base_addr(&self, id: AllocId) -> InterpResult<'tcx, *const u8> { let alloc = self.get_alloc_raw(id)?; Ok(alloc.base_addr()) } From 871c1dee33b91f20d90ff14441bab5bb93c55380 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Mon, 13 Feb 2023 23:32:06 -0500 Subject: [PATCH 4/7] Remove unused lifetime --- compiler/rustc_middle/src/mir/interpret/allocation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 974db3f440224..981fda244da52 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -271,7 +271,7 @@ impl AllocRange { // The constructors are all without extra; the extra gets added by a machine hook later. impl Allocation { /// Creates an allocation from an existing `Bytes` value - this is needed for miri FFI support - pub fn from_raw_bytes<'a>( + pub fn from_raw_bytes( bytes: Bytes, align: Align, mutability: Mutability, From 936b567d2e732afa1cc357c7faff2491d6d9212d Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Tue, 14 Feb 2023 15:26:47 -0500 Subject: [PATCH 5/7] Minimal changes to make miri work --- compiler/rustc_const_eval/src/interpret/machine.rs | 9 ++++++--- compiler/rustc_const_eval/src/interpret/memory.rs | 10 +++++++--- compiler/rustc_const_eval/src/interpret/place.rs | 6 ++++-- .../rustc_middle/src/mir/interpret/allocation.rs | 14 ++------------ compiler/rustc_middle/src/mir/interpret/mod.rs | 4 ++-- src/tools/miri/src/machine.rs | 3 ++- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 3a4df2da1ed51..92fa59aec6e5f 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -16,8 +16,8 @@ use rustc_target::spec::abi::Abi as CallAbi; use crate::const_eval::CheckAlignment; use super::{ - AllocId, AllocRange, Allocation, AllocBytes, ConstAllocation, Frame, ImmTy, InterpCx, InterpResult, - MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind, + AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx, + InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind, }; /// Data returned by Machine::stack_pop, @@ -111,7 +111,10 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Memory's allocation map type MemoryMap: AllocMap< AllocId, - (MemoryKind, Allocation), + ( + MemoryKind, + Allocation, + ), > + Default + Clone; diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index ead4ee7b5f791..a3764a7d14266 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -581,7 +581,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ptr: Pointer>, size: Size, align: Align, - ) -> InterpResult<'tcx, Option>> { + ) -> InterpResult<'tcx, Option>> + { let ptr_and_alloc = self.check_and_deref_ptr( ptr, size, @@ -653,7 +654,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ptr: Pointer>, size: Size, align: Align, - ) -> InterpResult<'tcx, Option>> { + ) -> InterpResult<'tcx, Option>> + { let parts = self.get_ptr_access(ptr, size, align)?; if let Some((alloc_id, offset, prov)) = parts { let tcx = *self.tcx; @@ -924,7 +926,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, } /// Reading and writing. -impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRefMut<'a, 'tcx, Prov, Extra, Bytes> { +impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes> + AllocRefMut<'a, 'tcx, Prov, Extra, Bytes> +{ /// `range` is relative to this allocation reference, not the base of the allocation. pub fn write_scalar(&mut self, range: AllocRange, val: Scalar) -> InterpResult<'tcx> { let range = self.range.subrange(range); diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index ad2d543854941..d15933c826b9a 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -340,7 +340,8 @@ where pub(super) fn get_place_alloc( &self, place: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Option>> { + ) -> InterpResult<'tcx, Option>> + { assert!(place.layout.is_sized()); assert!(!place.meta.has_meta()); let size = place.layout.size; @@ -351,7 +352,8 @@ where pub(super) fn get_place_alloc_mut( &mut self, place: &MPlaceTy<'tcx, M::Provenance>, - ) -> InterpResult<'tcx, Option>> { + ) -> InterpResult<'tcx, Option>> + { assert!(place.layout.is_sized()); assert!(!place.meta.has_meta()); let size = place.layout.size; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 981fda244da52..45477c4426672 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -32,13 +32,7 @@ pub use init_mask::{InitChunk, InitChunkIter}; /// Functionality required for the bytes of an `Allocation`. pub trait AllocBytes: - Clone - + fmt::Debug - + Eq - + PartialEq - + Hash - + Deref - + DerefMut + Clone + fmt::Debug + Eq + PartialEq + Hash + Deref + DerefMut { /// Adjust the bytes to the specified alignment -- by default, this is a no-op. fn adjust_to_align(self, _align: Align) -> Self; @@ -271,11 +265,7 @@ impl AllocRange { // The constructors are all without extra; the extra gets added by a machine hook later. impl Allocation { /// Creates an allocation from an existing `Bytes` value - this is needed for miri FFI support - pub fn from_raw_bytes( - bytes: Bytes, - align: Align, - mutability: Mutability, - ) -> Self { + pub fn from_raw_bytes(bytes: Bytes, align: Align, mutability: Mutability) -> Self { let size = Size::from_bytes(bytes.len()); Self { bytes, diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 4329bbf803076..1766d7a669804 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -127,8 +127,8 @@ pub use self::error::{ pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar}; pub use self::allocation::{ - alloc_range, AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, InitChunk, - InitChunkIter, + alloc_range, AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, + InitChunk, InitChunkIter, }; pub use self::pointer::{Pointer, PointerArithmetic, Provenance}; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 8bd1e802f8a52..00fdd57cb176b 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -771,10 +771,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { type Provenance = Provenance; type ProvenanceExtra = ProvenanceExtra; + type Bytes = Box<[u8]>; type MemoryMap = MonoHashMap< AllocId, - (MemoryKind, Allocation), + (MemoryKind, Allocation), >; const GLOBAL_KIND: Option = Some(MiriMemoryKind::Global); From 3a87a1885788a2cb9b7456ca74f281c6fff3005f Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Tue, 28 Feb 2023 15:39:17 -0500 Subject: [PATCH 6/7] Make zeroed return an Option --- .../src/mir/interpret/allocation.rs | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 45477c4426672..0628af747fa7d 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -42,11 +42,10 @@ pub trait AllocBytes: /// Create a zeroed `AllocBytes` of the specified size and alignment; /// call the callback error handler if there is an error in allocating the memory. - fn zeroed<'tcx, F: Fn() -> InterpError<'tcx>>( + fn zeroed( size: Size, _align: Align, - handle_alloc_fail: F, - ) -> Result>; + ) -> Option; } // Default `bytes` for `Allocation` is a `Box<[u8]>`. @@ -59,16 +58,14 @@ impl AllocBytes for Box<[u8]> { Box::<[u8]>::from(slice.into()) } - fn zeroed<'tcx, F: Fn() -> InterpError<'tcx>>( + fn zeroed( size: Size, _align: Align, - handle_alloc_fail: F, - ) -> Result> { - let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()) - .map_err(|_| handle_alloc_fail())?; + ) -> Option { + let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()).ok()?; // SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]> let bytes = unsafe { bytes.assume_init() }; - Ok(bytes) + Some(bytes) } } @@ -304,7 +301,7 @@ impl Allocation { /// /// If `panic_on_fail` is true, this will never return `Err`. pub fn uninit<'tcx>(size: Size, align: Align, panic_on_fail: bool) -> InterpResult<'tcx, Self> { - let handle_alloc_fail = || -> InterpError<'tcx> { + let bytes = Bytes::zeroed(size, align).ok_or_else(|| { // This results in an error that can happen non-deterministically, since the memory // available to the compiler can change between runs. Normally queries are always // deterministic. However, we can be non-deterministic here because all uses of const @@ -317,9 +314,7 @@ impl Allocation { tcx.sess.delay_span_bug(DUMMY_SP, "exhausted memory during interpretation") }); InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted) - }; - - let bytes = Bytes::zeroed(size, align, handle_alloc_fail)?; + })?; Ok(Allocation { bytes, From f26b0a29487c6501fa4c14b9b43b3fa0228001ba Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Wed, 1 Mar 2023 20:27:03 -0500 Subject: [PATCH 7/7] Format --- compiler/rustc_middle/src/mir/interpret/allocation.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 0628af747fa7d..48375ed301d22 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -42,10 +42,7 @@ pub trait AllocBytes: /// Create a zeroed `AllocBytes` of the specified size and alignment; /// call the callback error handler if there is an error in allocating the memory. - fn zeroed( - size: Size, - _align: Align, - ) -> Option; + fn zeroed(size: Size, _align: Align) -> Option; } // Default `bytes` for `Allocation` is a `Box<[u8]>`. @@ -58,10 +55,7 @@ impl AllocBytes for Box<[u8]> { Box::<[u8]>::from(slice.into()) } - fn zeroed( - size: Size, - _align: Align, - ) -> Option { + fn zeroed(size: Size, _align: Align) -> Option { let bytes = Box::<[u8]>::try_new_zeroed_slice(size.bytes_usize()).ok()?; // SAFETY: the box was zero-allocated, which is a valid initial value for Box<[u8]> let bytes = unsafe { bytes.assume_init() };