Allow non-Box
allocations in preparation for aligned const allocations for miri. Credit to emarteca for the code.
This commit is contained in:
parent
267cd1d2c5
commit
6f407d67b8
6 changed files with 120 additions and 48 deletions
|
@ -16,7 +16,7 @@ use rustc_target::spec::abi::Abi as CallAbi;
|
||||||
use crate::const_eval::CheckAlignment;
|
use crate::const_eval::CheckAlignment;
|
||||||
|
|
||||||
use super::{
|
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,
|
MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -105,10 +105,13 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||||
/// Extra data stored in every allocation.
|
/// Extra data stored in every allocation.
|
||||||
type AllocExtra: Debug + Clone + 'static;
|
type AllocExtra: Debug + Clone + 'static;
|
||||||
|
|
||||||
|
/// Type for the bytes of the allocation.
|
||||||
|
type Bytes: AllocBytes + 'static;
|
||||||
|
|
||||||
/// Memory's allocation map
|
/// Memory's allocation map
|
||||||
type MemoryMap: AllocMap<
|
type MemoryMap: AllocMap<
|
||||||
AllocId,
|
AllocId,
|
||||||
(MemoryKind<Self::MemoryKind>, Allocation<Self::Provenance, Self::AllocExtra>),
|
(MemoryKind<Self::MemoryKind>, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>),
|
||||||
> + Default
|
> + Default
|
||||||
+ Clone;
|
+ Clone;
|
||||||
|
|
||||||
|
@ -338,7 +341,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
|
||||||
id: AllocId,
|
id: AllocId,
|
||||||
alloc: Cow<'b, Allocation>,
|
alloc: Cow<'b, Allocation>,
|
||||||
kind: Option<MemoryKind<Self::MemoryKind>>,
|
kind: Option<MemoryKind<Self::MemoryKind>>,
|
||||||
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra>>>;
|
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>;
|
||||||
|
|
||||||
fn eval_inline_asm(
|
fn eval_inline_asm(
|
||||||
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
|
||||||
|
@ -459,6 +462,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
|
||||||
|
|
||||||
type AllocExtra = ();
|
type AllocExtra = ();
|
||||||
type FrameExtra = ();
|
type FrameExtra = ();
|
||||||
|
type Bytes = Box<[u8]>;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn use_addr_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
|
fn use_addr_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
|
||||||
|
|
|
@ -21,8 +21,9 @@ use rustc_target::abi::{Align, HasDataLayout, Size};
|
||||||
use crate::const_eval::CheckAlignment;
|
use crate::const_eval::CheckAlignment;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc, InterpCx,
|
alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg,
|
||||||
InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance, Scalar,
|
GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Provenance,
|
||||||
|
Scalar,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
#[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
|
/// A reference to some allocation that was already bounds-checked for the given region
|
||||||
/// and had the on-access machine hooks run.
|
/// and had the on-access machine hooks run.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct AllocRef<'a, 'tcx, Prov: Provenance, Extra> {
|
pub struct AllocRef<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes = Box<[u8]>> {
|
||||||
alloc: &'a Allocation<Prov, Extra>,
|
alloc: &'a Allocation<Prov, Extra, Bytes>,
|
||||||
range: AllocRange,
|
range: AllocRange,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
alloc_id: AllocId,
|
alloc_id: AllocId,
|
||||||
}
|
}
|
||||||
/// A reference to some allocation that was already bounds-checked for the given region
|
/// A reference to some allocation that was already bounds-checked for the given region
|
||||||
/// and had the on-access machine hooks run.
|
/// and had the on-access machine hooks run.
|
||||||
pub struct AllocRefMut<'a, 'tcx, Prov: Provenance, Extra> {
|
pub struct AllocRefMut<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes = Box<[u8]>> {
|
||||||
alloc: &'a mut Allocation<Prov, Extra>,
|
alloc: &'a mut Allocation<Prov, Extra, Bytes>,
|
||||||
range: AllocRange,
|
range: AllocRange,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
alloc_id: AllocId,
|
alloc_id: AllocId,
|
||||||
|
@ -483,7 +484,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
&self,
|
&self,
|
||||||
id: AllocId,
|
id: AllocId,
|
||||||
is_write: bool,
|
is_write: bool,
|
||||||
) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::Provenance, M::AllocExtra>>> {
|
) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::Provenance, M::AllocExtra, M::Bytes>>> {
|
||||||
let (alloc, def_id) = match self.tcx.try_get_global_alloc(id) {
|
let (alloc, def_id) = match self.tcx.try_get_global_alloc(id) {
|
||||||
Some(GlobalAlloc::Memory(mem)) => {
|
Some(GlobalAlloc::Memory(mem)) => {
|
||||||
// Memory of a constant or promoted or anonymous memory referenced by a static.
|
// 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.
|
/// Gives raw access to the `Allocation`, without bounds or alignment checks.
|
||||||
/// The caller is responsible for calling the access hooks!
|
/// 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(
|
fn get_alloc_raw(
|
||||||
&self,
|
&self,
|
||||||
id: AllocId,
|
id: AllocId,
|
||||||
) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra>> {
|
) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra, M::Bytes>> {
|
||||||
// The error type of the inner closure here is somewhat funny. We have two
|
// 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
|
// 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.
|
// `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<Option<M::Provenance>>,
|
ptr: Pointer<Option<M::Provenance>>,
|
||||||
size: Size,
|
size: Size,
|
||||||
align: Align,
|
align: Align,
|
||||||
) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra>>> {
|
) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> {
|
||||||
let ptr_and_alloc = self.check_and_deref_ptr(
|
let ptr_and_alloc = self.check_and_deref_ptr(
|
||||||
ptr,
|
ptr,
|
||||||
size,
|
size,
|
||||||
|
@ -612,7 +624,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
fn get_alloc_raw_mut(
|
fn get_alloc_raw_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
id: AllocId,
|
id: AllocId,
|
||||||
) -> InterpResult<'tcx, (&mut Allocation<M::Provenance, M::AllocExtra>, &mut M)> {
|
) -> InterpResult<'tcx, (&mut Allocation<M::Provenance, M::AllocExtra, M::Bytes>, &mut M)> {
|
||||||
// We have "NLL problem case #3" here, which cannot be worked around without loss of
|
// 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.
|
// efficiency even for the common case where the key is in the map.
|
||||||
// <https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions>
|
// <https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions>
|
||||||
|
@ -641,7 +653,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
ptr: Pointer<Option<M::Provenance>>,
|
ptr: Pointer<Option<M::Provenance>>,
|
||||||
size: Size,
|
size: Size,
|
||||||
align: Align,
|
align: Align,
|
||||||
) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra>>> {
|
) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> {
|
||||||
let parts = self.get_ptr_access(ptr, size, align)?;
|
let parts = self.get_ptr_access(ptr, size, align)?;
|
||||||
if let Some((alloc_id, offset, prov)) = parts {
|
if let Some((alloc_id, offset, prov)) = parts {
|
||||||
let tcx = *self.tcx;
|
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> {
|
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 {
|
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
// Cannot be a closure because it is generic in `Prov`, `Extra`.
|
// 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<'_>,
|
fmt: &mut std::fmt::Formatter<'_>,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
allocs_to_print: &mut VecDeque<AllocId>,
|
allocs_to_print: &mut VecDeque<AllocId>,
|
||||||
alloc: &Allocation<Prov, Extra>,
|
alloc: &Allocation<Prov, Extra, Bytes>,
|
||||||
) -> std::fmt::Result {
|
) -> std::fmt::Result {
|
||||||
for alloc_id in alloc.provenance().provenances().filter_map(|prov| prov.get_alloc_id())
|
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.
|
/// 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.
|
/// `range` is relative to this allocation reference, not the base of the allocation.
|
||||||
pub fn write_scalar(&mut self, range: AllocRange, val: Scalar<Prov>) -> InterpResult<'tcx> {
|
pub fn write_scalar(&mut self, range: AllocRange, val: Scalar<Prov>) -> InterpResult<'tcx> {
|
||||||
let range = self.range.subrange(range);
|
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.
|
/// `range` is relative to this allocation reference, not the base of the allocation.
|
||||||
pub fn read_scalar(
|
pub fn read_scalar(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -340,7 +340,7 @@ where
|
||||||
pub(super) fn get_place_alloc(
|
pub(super) fn get_place_alloc(
|
||||||
&self,
|
&self,
|
||||||
place: &MPlaceTy<'tcx, M::Provenance>,
|
place: &MPlaceTy<'tcx, M::Provenance>,
|
||||||
) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra>>> {
|
) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> {
|
||||||
assert!(place.layout.is_sized());
|
assert!(place.layout.is_sized());
|
||||||
assert!(!place.meta.has_meta());
|
assert!(!place.meta.has_meta());
|
||||||
let size = place.layout.size;
|
let size = place.layout.size;
|
||||||
|
@ -351,7 +351,7 @@ where
|
||||||
pub(super) fn get_place_alloc_mut(
|
pub(super) fn get_place_alloc_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
place: &MPlaceTy<'tcx, M::Provenance>,
|
place: &MPlaceTy<'tcx, M::Provenance>,
|
||||||
) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra>>> {
|
) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>> {
|
||||||
assert!(place.layout.is_sized());
|
assert!(place.layout.is_sized());
|
||||||
assert!(!place.meta.has_meta());
|
assert!(!place.meta.has_meta());
|
||||||
let size = place.layout.size;
|
let size = place.layout.size;
|
||||||
|
|
|
@ -8,7 +8,8 @@ mod tests;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash;
|
use std::hash;
|
||||||
use std::ops::Range;
|
use std::hash::Hash;
|
||||||
|
use std::ops::{Deref, DerefMut, Range};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use either::{Left, Right};
|
use either::{Left, Right};
|
||||||
|
@ -29,6 +30,54 @@ use provenance_map::*;
|
||||||
|
|
||||||
pub use init_mask::{InitChunk, InitChunkIter};
|
pub use init_mask::{InitChunk, InitChunkIter};
|
||||||
|
|
||||||
|
/// Functionality required for the bytes of an `Allocation`.
|
||||||
|
pub trait AllocBytes:
|
||||||
|
Clone
|
||||||
|
+ fmt::Debug
|
||||||
|
+ Eq
|
||||||
|
+ PartialEq
|
||||||
|
+ Hash
|
||||||
|
+ Deref<Target = [u8]>
|
||||||
|
+ DerefMut<Target = [u8]>
|
||||||
|
{
|
||||||
|
/// 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<Cow<'a, [u8]>>, _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<Self, InterpError<'tcx>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<Cow<'a, [u8]>>, _align: Align) -> Self {
|
||||||
|
Box::<[u8]>::from(slice.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zeroed<'tcx, F: Fn() -> InterpError<'tcx>>(
|
||||||
|
size: Size,
|
||||||
|
_align: Align,
|
||||||
|
handle_alloc_fail: F,
|
||||||
|
) -> Result<Self, InterpError<'tcx>> {
|
||||||
|
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.
|
/// 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
|
/// 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.
|
// hashed. (see the `Hash` impl below for more details), so the impl is not derived.
|
||||||
#[derive(Clone, Eq, PartialEq, TyEncodable, TyDecodable)]
|
#[derive(Clone, Eq, PartialEq, TyEncodable, TyDecodable)]
|
||||||
#[derive(HashStable)]
|
#[derive(HashStable)]
|
||||||
pub struct Allocation<Prov: Provenance = AllocId, Extra = ()> {
|
pub struct Allocation<Prov: Provenance = AllocId, Extra = (), Bytes = Box<[u8]>> {
|
||||||
/// The actual bytes of the allocation.
|
/// The actual bytes of the allocation.
|
||||||
/// Note that the bytes of a pointer represent the offset of the pointer.
|
/// 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.
|
/// 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.,
|
/// 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
|
/// 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.
|
// The constructors are all without extra; the extra gets added by a machine hook later.
|
||||||
impl<Prov: Provenance> Allocation<Prov> {
|
impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
|
||||||
/// Creates an allocation initialized by the given bytes
|
/// Creates an allocation initialized by the given bytes
|
||||||
pub fn from_bytes<'a>(
|
pub fn from_bytes<'a>(
|
||||||
slice: impl Into<Cow<'a, [u8]>>,
|
slice: impl Into<Cow<'a, [u8]>>,
|
||||||
align: Align,
|
align: Align,
|
||||||
mutability: Mutability,
|
mutability: Mutability,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let bytes = Box::<[u8]>::from(slice.into());
|
let bytes = Bytes::from_bytes(slice, align);
|
||||||
let size = Size::from_bytes(bytes.len());
|
let size = Size::from_bytes(bytes.len());
|
||||||
Self {
|
Self {
|
||||||
bytes,
|
bytes,
|
||||||
|
@ -248,7 +297,7 @@ impl<Prov: Provenance> Allocation<Prov> {
|
||||||
///
|
///
|
||||||
/// If `panic_on_fail` is true, this will never return `Err`.
|
/// 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> {
|
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
|
// 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
|
// 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
|
// deterministic. However, we can be non-deterministic here because all uses of const
|
||||||
|
@ -261,9 +310,10 @@ impl<Prov: Provenance> Allocation<Prov> {
|
||||||
tcx.sess.delay_span_bug(DUMMY_SP, "exhausted memory during interpretation")
|
tcx.sess.delay_span_bug(DUMMY_SP, "exhausted memory during interpretation")
|
||||||
});
|
});
|
||||||
InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)
|
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 {
|
Ok(Allocation {
|
||||||
bytes,
|
bytes,
|
||||||
provenance: ProvenanceMap::new(),
|
provenance: ProvenanceMap::new(),
|
||||||
|
@ -275,7 +325,7 @@ impl<Prov: Provenance> Allocation<Prov> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Allocation {
|
impl<Bytes: AllocBytes> Allocation<AllocId, (), Bytes> {
|
||||||
/// Adjust allocation from the ones in tcx to a custom Machine instance
|
/// Adjust allocation from the ones in tcx to a custom Machine instance
|
||||||
/// with a different Provenance and Extra type.
|
/// with a different Provenance and Extra type.
|
||||||
pub fn adjust_from_tcx<Prov: Provenance, Extra, Err>(
|
pub fn adjust_from_tcx<Prov: Provenance, Extra, Err>(
|
||||||
|
@ -283,9 +333,11 @@ impl Allocation {
|
||||||
cx: &impl HasDataLayout,
|
cx: &impl HasDataLayout,
|
||||||
extra: Extra,
|
extra: Extra,
|
||||||
mut adjust_ptr: impl FnMut(Pointer<AllocId>) -> Result<Pointer<Prov>, Err>,
|
mut adjust_ptr: impl FnMut(Pointer<AllocId>) -> Result<Pointer<Prov>, Err>,
|
||||||
) -> Result<Allocation<Prov, Extra>, Err> {
|
) -> Result<Allocation<Prov, Extra, Bytes>, Err> {
|
||||||
// Compute new pointer provenance, which also adjusts the bytes.
|
// Compute new pointer provenance, which also adjusts the bytes, and realign the pointer if
|
||||||
let mut bytes = self.bytes;
|
// necessary.
|
||||||
|
let mut bytes = self.bytes.adjust_to_align(self.align);
|
||||||
|
|
||||||
let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len());
|
let mut new_provenance = Vec::with_capacity(self.provenance.ptrs().len());
|
||||||
let ptr_size = cx.data_layout().pointer_size.bytes_usize();
|
let ptr_size = cx.data_layout().pointer_size.bytes_usize();
|
||||||
let endian = cx.data_layout().endian;
|
let endian = cx.data_layout().endian;
|
||||||
|
@ -311,7 +363,7 @@ impl Allocation {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Raw accessors. Provide access to otherwise private bytes.
|
/// Raw accessors. Provide access to otherwise private bytes.
|
||||||
impl<Prov: Provenance, Extra> Allocation<Prov, Extra> {
|
impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> {
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.bytes.len()
|
self.bytes.len()
|
||||||
}
|
}
|
||||||
|
@ -340,7 +392,11 @@ impl<Prov: Provenance, Extra> Allocation<Prov, Extra> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Byte accessors.
|
/// Byte accessors.
|
||||||
impl<Prov: Provenance, Extra> Allocation<Prov, Extra> {
|
impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> {
|
||||||
|
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
|
/// This is the entirely abstraction-violating way to just grab the raw bytes without
|
||||||
/// caring about provenance or initialization.
|
/// caring about provenance or initialization.
|
||||||
///
|
///
|
||||||
|
@ -412,7 +468,7 @@ impl<Prov: Provenance, Extra> Allocation<Prov, Extra> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reading and writing.
|
/// Reading and writing.
|
||||||
impl<Prov: Provenance, Extra> Allocation<Prov, Extra> {
|
impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> {
|
||||||
/// Sets the init bit for the given range.
|
/// Sets the init bit for the given range.
|
||||||
fn mark_init(&mut self, range: AllocRange, is_init: bool) {
|
fn mark_init(&mut self, range: AllocRange, is_init: bool) {
|
||||||
if range.size.bytes() == 0 {
|
if range.size.bytes() == 0 {
|
||||||
|
|
|
@ -127,7 +127,7 @@ pub use self::error::{
|
||||||
pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar};
|
pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar};
|
||||||
|
|
||||||
pub use self::allocation::{
|
pub use self::allocation::{
|
||||||
alloc_range, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, InitChunk,
|
alloc_range, AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, InitChunk,
|
||||||
InitChunkIter,
|
InitChunkIter,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@ use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_index::vec::Idx;
|
use rustc_index::vec::Idx;
|
||||||
use rustc_middle::mir::interpret::{
|
use rustc_middle::mir::interpret::{
|
||||||
alloc_range, read_target_uint, AllocId, Allocation, ConstAllocation, ConstValue, GlobalAlloc,
|
alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, ConstAllocation, ConstValue,
|
||||||
Pointer, Provenance,
|
GlobalAlloc, Pointer, Provenance,
|
||||||
};
|
};
|
||||||
use rustc_middle::mir::visit::Visitor;
|
use rustc_middle::mir::visit::Visitor;
|
||||||
use rustc_middle::mir::*;
|
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
|
/// After the hex dump, an ascii dump follows, replacing all unprintable characters (control
|
||||||
/// characters or characters whose value is larger than 127) with a `.`
|
/// characters or characters whose value is larger than 127) with a `.`
|
||||||
/// This also prints provenance adequately.
|
/// 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>,
|
tcx: TyCtxt<'tcx>,
|
||||||
alloc: &'a Allocation<Prov, Extra>,
|
alloc: &'a Allocation<Prov, Extra, Bytes>,
|
||||||
) -> RenderAllocation<'a, 'tcx, Prov, Extra> {
|
) -> RenderAllocation<'a, 'tcx, Prov, Extra, Bytes> {
|
||||||
RenderAllocation { tcx, alloc }
|
RenderAllocation { tcx, alloc }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct RenderAllocation<'a, 'tcx, Prov: Provenance, Extra> {
|
pub struct RenderAllocation<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
alloc: &'a Allocation<Prov, Extra>,
|
alloc: &'a Allocation<Prov, Extra, Bytes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx, Prov: Provenance, Extra> std::fmt::Display
|
impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> std::fmt::Display
|
||||||
for RenderAllocation<'a, 'tcx, Prov, Extra>
|
for RenderAllocation<'a, 'tcx, Prov, Extra, Bytes>
|
||||||
{
|
{
|
||||||
fn fmt(&self, w: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, w: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let RenderAllocation { tcx, alloc } = *self;
|
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
|
/// 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
|
/// is only one line). Note that your prefix should contain a trailing space as the lines are
|
||||||
/// printed directly after it.
|
/// 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>,
|
tcx: TyCtxt<'tcx>,
|
||||||
alloc: &Allocation<Prov, Extra>,
|
alloc: &Allocation<Prov, Extra, Bytes>,
|
||||||
w: &mut dyn std::fmt::Write,
|
w: &mut dyn std::fmt::Write,
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
) -> std::fmt::Result {
|
) -> std::fmt::Result {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue