diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 81b9d73b9528c..a430d9dc797f1 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -472,8 +472,9 @@ fn report_validation_error<'tcx>( backtrace.print_backtrace(); let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id); - let (size, align, _) = ecx.get_alloc_info(alloc_id); - let raw_bytes = errors::RawBytesNote { size: size.bytes(), align: align.bytes(), bytes }; + let info = ecx.get_alloc_info(alloc_id); + let raw_bytes = + errors::RawBytesNote { size: info.size.bytes(), align: info.align.bytes(), bytes }; crate::const_eval::report( *ecx.tcx, diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 1ad8ffa4b53fc..09635c96e57cd 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -14,10 +14,9 @@ use std::{fmt, mem, ptr}; use rustc_abi::{Align, HasDataLayout, Size}; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_hir::def::DefKind; use rustc_middle::bug; use rustc_middle::mir::display_allocation; -use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use tracing::{debug, instrument, trace}; use super::{ @@ -72,6 +71,21 @@ pub enum AllocKind { Dead, } +/// Metadata about an `AllocId`. +#[derive(Copy, Clone, PartialEq, Debug)] +pub struct AllocInfo { + pub size: Size, + pub align: Align, + pub kind: AllocKind, + pub mutbl: Mutability, +} + +impl AllocInfo { + fn new(size: Size, align: Align, kind: AllocKind, mutbl: Mutability) -> Self { + Self { size, align, kind, mutbl } + } +} + /// The value of a function pointer. #[derive(Debug, Copy, Clone)] pub enum FnVal<'tcx, Other> { @@ -524,17 +538,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { match self.ptr_try_get_alloc_id(ptr, 0) { Err(addr) => is_offset_misaligned(addr, align), Ok((alloc_id, offset, _prov)) => { - let (_size, alloc_align, kind) = self.get_alloc_info(alloc_id); - if let Some(misalign) = - M::alignment_check(self, alloc_id, alloc_align, kind, offset, align) - { + let alloc_info = self.get_alloc_info(alloc_id); + if let Some(misalign) = M::alignment_check( + self, + alloc_id, + alloc_info.align, + alloc_info.kind, + offset, + align, + ) { Some(misalign) } else if M::Provenance::OFFSET_IS_ADDR { is_offset_misaligned(ptr.addr().bytes(), align) } else { // Check allocation alignment and offset alignment. - if alloc_align.bytes() < align.bytes() { - Some(Misalignment { has: alloc_align, required: align }) + if alloc_info.align.bytes() < align.bytes() { + Some(Misalignment { has: alloc_info.align, required: align }) } else { is_offset_misaligned(offset.bytes(), align) } @@ -818,82 +837,45 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Obtain the size and alignment of an allocation, even if that allocation has /// been deallocated. - pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) { + pub fn get_alloc_info(&self, id: AllocId) -> AllocInfo { // # Regular allocations // Don't use `self.get_raw` here as that will // a) cause cycles in case `id` refers to a static // b) duplicate a global's allocation in miri if let Some((_, alloc)) = self.memory.alloc_map.get(id) { - return (alloc.size(), alloc.align, AllocKind::LiveData); + return AllocInfo::new( + alloc.size(), + alloc.align, + AllocKind::LiveData, + alloc.mutability, + ); } // # Function pointers // (both global from `alloc_map` and local from `extra_fn_ptr_map`) if self.get_fn_alloc(id).is_some() { - return (Size::ZERO, Align::ONE, AllocKind::Function); + return AllocInfo::new(Size::ZERO, Align::ONE, AllocKind::Function, Mutability::Not); } - // # Statics - // Can't do this in the match argument, we may get cycle errors since the lock would - // be held throughout the match. - match self.tcx.try_get_global_alloc(id) { - Some(GlobalAlloc::Static(def_id)) => { - // Thread-local statics do not have a constant address. They *must* be accessed via - // `ThreadLocalRef`; we can never have a pointer to them as a regular constant value. - assert!(!self.tcx.is_thread_local_static(def_id)); - - let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { - bug!("GlobalAlloc::Static is not a static") - }; - - let (size, align) = if nested { - // Nested anonymous statics are untyped, so let's get their - // size and alignment from the allocation itself. This always - // succeeds, as the query is fed at DefId creation time, so no - // evaluation actually occurs. - let alloc = self.tcx.eval_static_initializer(def_id).unwrap(); - (alloc.0.size(), alloc.0.align) - } else { - // Use size and align of the type for everything else. We need - // to do that to - // * avoid cycle errors in case of self-referential statics, - // * be able to get information on extern statics. - let ty = self - .tcx - .type_of(def_id) - .no_bound_vars() - .expect("statics should not have generic parameters"); - let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap(); - assert!(layout.is_sized()); - (layout.size, layout.align.abi) - }; - (size, align, AllocKind::LiveData) - } - Some(GlobalAlloc::Memory(alloc)) => { - // Need to duplicate the logic here, because the global allocations have - // different associated types than the interpreter-local ones. - let alloc = alloc.inner(); - (alloc.size(), alloc.align, AllocKind::LiveData) - } - Some(GlobalAlloc::Function { .. }) => { - bug!("We already checked function pointers above") - } - Some(GlobalAlloc::VTable(..)) => { - // No data to be accessed here. But vtables are pointer-aligned. - return (Size::ZERO, self.tcx.data_layout.pointer_align.abi, AllocKind::VTable); - } - // The rest must be dead. - None => { - // Deallocated pointers are allowed, we should be able to find - // them in the map. - let (size, align) = *self - .memory - .dead_alloc_map - .get(&id) - .expect("deallocated pointers should all be recorded in `dead_alloc_map`"); - (size, align, AllocKind::Dead) - } + // # Global allocations + if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) { + let (size, align) = global_alloc.size_and_align(*self.tcx, self.param_env); + let mutbl = global_alloc.mutability(*self.tcx, self.param_env); + let kind = match global_alloc { + GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData, + GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"), + GlobalAlloc::VTable { .. } => AllocKind::VTable, + }; + return AllocInfo::new(size, align, kind, mutbl); } + + // # Dead pointers + let (size, align) = *self + .memory + .dead_alloc_map + .get(&id) + .expect("deallocated pointers should all be recorded in `dead_alloc_map`"); + AllocInfo::new(size, align, AllocKind::Dead, Mutability::Not) } /// Obtain the size and alignment of a *live* allocation. @@ -902,11 +884,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { id: AllocId, msg: CheckInAllocMsg, ) -> InterpResult<'tcx, (Size, Align)> { - let (size, align, kind) = self.get_alloc_info(id); - if matches!(kind, AllocKind::Dead) { + let info = self.get_alloc_info(id); + if matches!(info.kind, AllocKind::Dead) { throw_ub!(PointerUseAfterFree(id, msg)) } - interp_ok((size, align)) + interp_ok((info.size, info.align)) } fn get_fn_alloc(&self, id: AllocId) -> Option> { @@ -1458,7 +1440,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let ptr = scalar.to_pointer(self)?; match self.ptr_try_get_alloc_id(ptr, 0) { Ok((alloc_id, offset, _)) => { - let (size, _align, _kind) = self.get_alloc_info(alloc_id); + let size = self.get_alloc_info(alloc_id).size; // If the pointer is out-of-bounds, it may be null. // Note that one-past-the-end (offset == size) is still inbounds, and never null. offset > size diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index 5e84626f77e7a..f5792aba2075c 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -31,7 +31,7 @@ pub use self::intern::{ }; pub(crate) use self::intrinsics::eval_nullary_intrinsic; pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine}; -pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; +pub use self::memory::{AllocInfo, AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; use self::operand::Operand; pub use self::operand::{ImmTy, Immediate, OpTy}; pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable}; diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index cd2c1ef36132e..3a68db9f7f74b 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -31,8 +31,8 @@ use tracing::trace; use super::machine::AllocMap; use super::{ - AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, - MPlaceTy, Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub, + AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, + Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub, format_interp_error, }; @@ -557,9 +557,20 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr(), 0) { - if let Some(GlobalAlloc::Static(did)) = - self.ecx.tcx.try_get_global_alloc(alloc_id) - { + // Everything should be already interned. + let Some(global_alloc) = self.ecx.tcx.try_get_global_alloc(alloc_id) else { + assert!(self.ecx.memory.alloc_map.get(alloc_id).is_none()); + // We can't have *any* references to non-existing allocations in const-eval + // as the rest of rustc isn't happy with them... so we throw an error, even + // though for zero-sized references this isn't really UB. + // A potential future alternative would be to resurrect this as a zero-sized allocation + // (which codegen will then compile to an aligned dummy pointer anyway). + throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind }); + }; + let (size, _align) = + global_alloc.size_and_align(*self.ecx.tcx, self.ecx.param_env); + + if let GlobalAlloc::Static(did) = global_alloc { let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { bug!() }; @@ -593,17 +604,6 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } } - // Dangling and Mutability check. - let (size, _align, alloc_kind) = self.ecx.get_alloc_info(alloc_id); - if alloc_kind == AllocKind::Dead { - // This can happen for zero-sized references. We can't have *any* references to - // non-existing allocations in const-eval though, interning rejects them all as - // the rest of rustc isn't happy with them... so we throw an error, even though - // this isn't really UB. - // A potential future alternative would be to resurrect this as a zero-sized allocation - // (which codegen will then compile to an aligned dummy pointer anyway). - throw_validation_failure!(self.path, DanglingPtrUseAfterFree { ptr_kind }); - } // If this allocation has size zero, there is no actual mutability here. if size != Size::ZERO { // Determine whether this pointer expects to be pointing to something mutable. @@ -618,7 +618,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } }; // Determine what it actually points to. - let alloc_actual_mutbl = mutability(self.ecx, alloc_id); + let alloc_actual_mutbl = + global_alloc.mutability(*self.ecx.tcx, self.ecx.param_env); // Mutable pointer to immutable memory is no good. if ptr_expected_mutbl == Mutability::Mut && alloc_actual_mutbl == Mutability::Not @@ -842,9 +843,16 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } fn in_mutable_memory(&self, val: &PlaceTy<'tcx, M::Provenance>) -> bool { + debug_assert!(self.ctfe_mode.is_some()); if let Some(mplace) = val.as_mplace_or_local().left() { if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) { - mutability(self.ecx, alloc_id).is_mut() + let tcx = *self.ecx.tcx; + // Everything must be already interned. + let mutbl = tcx.global_alloc(alloc_id).mutability(tcx, self.ecx.param_env); + if let Some((_, alloc)) = self.ecx.memory.alloc_map.get(alloc_id) { + assert_eq!(alloc.mutability, mutbl); + } + mutbl.is_mut() } else { // No memory at all. false @@ -1016,53 +1024,6 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } } -/// Returns whether the allocation is mutable, and whether it's actually a static. -/// For "root" statics we look at the type to account for interior -/// mutability; for nested statics we have no type and directly use the annotated mutability. -fn mutability<'tcx>(ecx: &InterpCx<'tcx, impl Machine<'tcx>>, alloc_id: AllocId) -> Mutability { - // Let's see what kind of memory this points to. - // We're not using `try_global_alloc` since dangling pointers have already been handled. - match ecx.tcx.global_alloc(alloc_id) { - GlobalAlloc::Static(did) => { - let DefKind::Static { safety: _, mutability, nested } = ecx.tcx.def_kind(did) else { - bug!() - }; - if nested { - assert!( - ecx.memory.alloc_map.get(alloc_id).is_none(), - "allocations of nested statics are already interned: {alloc_id:?}, {did:?}" - ); - // Nested statics in a `static` are never interior mutable, - // so just use the declared mutability. - mutability - } else { - let mutability = match mutability { - Mutability::Not - if !ecx - .tcx - .type_of(did) - .no_bound_vars() - .expect("statics should not have generic parameters") - .is_freeze(*ecx.tcx, ty::ParamEnv::reveal_all()) => - { - Mutability::Mut - } - _ => mutability, - }; - if let Some((_, alloc)) = ecx.memory.alloc_map.get(alloc_id) { - assert_eq!(alloc.mutability, mutability); - } - mutability - } - } - GlobalAlloc::Memory(alloc) => alloc.inner().mutability, - GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => { - // These are immutable, we better don't allow mutable pointers here. - Mutability::Not - } - } -} - impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, 'tcx, M> { type V = PlaceTy<'tcx, M::Provenance>; diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index b0c0e1be50064..f225ad94aa704 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -12,11 +12,12 @@ use std::io::{Read, Write}; use std::num::NonZero; use std::{fmt, io}; -use rustc_abi::{AddressSpace, Endian, HasDataLayout}; -use rustc_ast::LitKind; +use rustc_abi::{AddressSpace, Align, Endian, HasDataLayout, Size}; +use rustc_ast::{LitKind, Mutability}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lock; use rustc_errors::ErrorGuaranteed; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -45,7 +46,7 @@ pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance}; pub use self::value::Scalar; use crate::mir; use crate::ty::codec::{TyDecoder, TyEncoder}; -use crate::ty::{self, Instance, Ty, TyCtxt}; +use crate::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; /// Uniquely identifies one of the following: /// - A constant @@ -310,6 +311,85 @@ impl<'tcx> GlobalAlloc<'tcx> { } } } + + pub fn mutability(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Mutability { + // Let's see what kind of memory we are. + match self { + GlobalAlloc::Static(did) => { + let DefKind::Static { safety: _, mutability, nested } = tcx.def_kind(did) else { + bug!() + }; + if nested { + // Nested statics in a `static` are never interior mutable, + // so just use the declared mutability. + if cfg!(debug_assertions) { + let alloc = tcx.eval_static_initializer(did).unwrap(); + assert_eq!(alloc.0.mutability, mutability); + } + mutability + } else { + let mutability = match mutability { + Mutability::Not + if !tcx + .type_of(did) + .no_bound_vars() + .expect("statics should not have generic parameters") + .is_freeze(tcx, param_env) => + { + Mutability::Mut + } + _ => mutability, + }; + mutability + } + } + GlobalAlloc::Memory(alloc) => alloc.inner().mutability, + GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => { + // These are immutable. + Mutability::Not + } + } + } + + pub fn size_and_align(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> (Size, Align) { + match self { + GlobalAlloc::Static(def_id) => { + let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { + bug!("GlobalAlloc::Static is not a static") + }; + + if nested { + // Nested anonymous statics are untyped, so let's get their + // size and alignment from the allocation itself. This always + // succeeds, as the query is fed at DefId creation time, so no + // evaluation actually occurs. + let alloc = tcx.eval_static_initializer(def_id).unwrap(); + (alloc.0.size(), alloc.0.align) + } else { + // Use size and align of the type for everything else. We need + // to do that to + // * avoid cycle errors in case of self-referential statics, + // * be able to get information on extern statics. + let ty = tcx + .type_of(def_id) + .no_bound_vars() + .expect("statics should not have generic parameters"); + let layout = tcx.layout_of(param_env.and(ty)).unwrap(); + assert!(layout.is_sized()); + (layout.size, layout.align.abi) + } + } + GlobalAlloc::Memory(alloc) => { + let alloc = alloc.inner(); + (alloc.size(), alloc.align) + } + GlobalAlloc::Function { .. } => (Size::ZERO, Align::ONE), + GlobalAlloc::VTable(..) => { + // No data to be accessed here. But vtables are pointer-aligned. + return (Size::ZERO, tcx.data_layout.pointer_align.abi); + } + } + } } pub const CTFE_ALLOC_SALT: usize = 0; diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 7b377a1c4cdfc..b9d82a086203d 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -134,7 +134,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // entered for addresses that are not the base address, so even zero-sized // allocations will get recognized at their base address -- but all other // allocations will *not* be recognized at their "end" address. - let size = ecx.get_alloc_info(alloc_id).0; + let size = ecx.get_alloc_info(alloc_id).size; if offset < size.bytes() { Some(alloc_id) } else { None } } }?; @@ -157,25 +157,25 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, u64> { let ecx = self.eval_context_ref(); let mut rng = ecx.machine.rng.borrow_mut(); - let (size, align, kind) = ecx.get_alloc_info(alloc_id); + let info = ecx.get_alloc_info(alloc_id); // This is either called immediately after allocation (and then cached), or when // adjusting `tcx` pointers (which never get freed). So assert that we are looking // at a live allocation. This also ensures that we never re-assign an address to an // allocation that previously had an address, but then was freed and the address // information was removed. - assert!(!matches!(kind, AllocKind::Dead)); + assert!(!matches!(info.kind, AllocKind::Dead)); // This allocation does not have a base address yet, pick or reuse one. if ecx.machine.native_lib.is_some() { // In native lib mode, we use the "real" address of the bytes for this allocation. // This ensures the interpreted program and native code have the same view of memory. - let base_ptr = match kind { + let base_ptr = match info.kind { AllocKind::LiveData => { if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { // For new global allocations, we always pre-allocate the memory to be able use the machine address directly. - let prepared_bytes = MiriAllocBytes::zeroed(size, align) + let prepared_bytes = MiriAllocBytes::zeroed(info.size, info.align) .unwrap_or_else(|| { - panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes") + panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes", size = info.size) }); let ptr = prepared_bytes.as_ptr(); // Store prepared allocation space to be picked up for use later. @@ -204,7 +204,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } // We are not in native lib mode, so we control the addresses ourselves. if let Some((reuse_addr, clock)) = - global_state.reuse.take_addr(&mut *rng, size, align, memory_kind, ecx.active_thread()) + global_state.reuse.take_addr(&mut *rng, info.size, info.align, memory_kind, ecx.active_thread()) { if let Some(clock) = clock { ecx.acquire_clock(&clock); @@ -220,14 +220,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { .next_base_addr .checked_add(slack) .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; - let base_addr = align_addr(base_addr, align.bytes()); + let base_addr = align_addr(base_addr, info.align.bytes()); // Remember next base address. If this allocation is zero-sized, leave a gap of at // least 1 to avoid two allocations having the same base address. (The logic in // `alloc_id_from_addr` assumes unique addresses, and different function/vtable pointers // need to be distinguishable!) global_state.next_base_addr = base_addr - .checked_add(max(size.bytes(), 1)) + .checked_add(max(info.size.bytes(), 1)) .ok_or_else(|| err_exhaust!(AddressSpaceFull))?; // Even if `Size` didn't overflow, we might still have filled up the address space. if global_state.next_base_addr > ecx.target_usize_max() { diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index 72319decb9430..4883613dea504 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -363,7 +363,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If it does exist, then we have the guarantee that the // pointer is readable, and the implicit read access inserted // will never cause UB on the pointer itself. - let (_, _, kind) = this.get_alloc_info(*alloc_id); + let kind = this.get_alloc_info(*alloc_id).kind; if matches!(kind, AllocKind::LiveData) { let alloc_extra = this.get_alloc_extra(*alloc_id)?; // can still fail for `extern static` let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap(); diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 47fe41d9ecdd8..16fcc26be33a1 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -626,7 +626,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(()) }; - let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id); + let alloc_kind = this.get_alloc_info(alloc_id).kind; match alloc_kind { AllocKind::LiveData => { // This should have alloc_extra data, but `get_alloc_extra` can still fail @@ -1017,7 +1017,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Function pointers and dead objects don't have an alloc_extra so we ignore them. // This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks. // NOT using `get_alloc_extra_mut` since this might be a read-only allocation! - let (_size, _align, kind) = this.get_alloc_info(alloc_id); + let kind = this.get_alloc_info(alloc_id).kind; match kind { AllocKind::LiveData => { // This should have alloc_extra data, but `get_alloc_extra` can still fail diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index 40467aa4bc1be..f92150758dc39 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -274,7 +274,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .insert(new_tag, protect); } - let alloc_kind = this.get_alloc_info(alloc_id).2; + let alloc_kind = this.get_alloc_info(alloc_id).kind; if !matches!(alloc_kind, AllocKind::LiveData) { assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here // There's not actually any bytes here where accesses could even be tracked. @@ -538,7 +538,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Function pointers and dead objects don't have an alloc_extra so we ignore them. // This is okay because accessing them is UB anyway, no need for any Tree Borrows checks. // NOT using `get_alloc_extra_mut` since this might be a read-only allocation! - let (_size, _align, kind) = this.get_alloc_info(alloc_id); + let kind = this.get_alloc_info(alloc_id).kind; match kind { AllocKind::LiveData => { // This should have alloc_extra data, but `get_alloc_extra` can still fail diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 72e8952c5437f..9668998aaa3a4 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1125,10 +1125,10 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { let Provenance::Concrete { alloc_id, .. } = ptr.provenance else { panic!("extern_statics cannot contain wildcards") }; - let (shim_size, shim_align, _kind) = ecx.get_alloc_info(alloc_id); + let info = ecx.get_alloc_info(alloc_id); let def_ty = ecx.tcx.type_of(def_id).instantiate_identity(); let extern_decl_layout = ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap(); - if extern_decl_layout.size != shim_size || extern_decl_layout.align.abi != shim_align { + if extern_decl_layout.size != info.size || extern_decl_layout.align.abi != info.align { throw_unsup_format!( "extern static `{link_name}` has been declared as `{krate}::{name}` \ with a size of {decl_size} bytes and alignment of {decl_align} bytes, \ @@ -1138,8 +1138,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { krate = ecx.tcx.crate_name(def_id.krate), decl_size = extern_decl_layout.size.bytes(), decl_align = extern_decl_layout.align.abi.bytes(), - shim_size = shim_size.bytes(), - shim_align = shim_align.bytes(), + shim_size = info.size.bytes(), + shim_align = info.align.bytes(), ) } interp_ok(ptr) diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 18578c7acc963..b903433692437 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -300,7 +300,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let id = this.read_scalar(id)?.to_u64()?; let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?; if let Some(id) = std::num::NonZero::new(id).map(AllocId) - && this.get_alloc_info(id).2 == AllocKind::LiveData + && this.get_alloc_info(id).kind == AllocKind::LiveData { this.print_borrow_state(id, show_unnamed)?; } else { @@ -409,7 +409,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } if let Ok((alloc_id, offset, ..)) = this.ptr_try_get_alloc_id(ptr, 0) { - let (_size, alloc_align, _kind) = this.get_alloc_info(alloc_id); + let alloc_align = this.get_alloc_info(alloc_id).align; // If the newly promised alignment is bigger than the native alignment of this // allocation, and bigger than the previously promised alignment, then set it. if align > alloc_align