Skip to content

Commit 0918ff6

Browse files
committed
make return type of get_alloc_info a struct, and reduce some code duplication with validity checking
1 parent 30a2ae6 commit 0918ff6

File tree

10 files changed

+74
-93
lines changed

10 files changed

+74
-93
lines changed

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -472,8 +472,9 @@ fn report_validation_error<'tcx>(
472472
backtrace.print_backtrace();
473473

474474
let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id);
475-
let (size, align, ..) = ecx.get_alloc_info(alloc_id);
476-
let raw_bytes = errors::RawBytesNote { size: size.bytes(), align: align.bytes(), bytes };
475+
let info = ecx.get_alloc_info(alloc_id);
476+
let raw_bytes =
477+
errors::RawBytesNote { size: info.size.bytes(), align: info.align.bytes(), bytes };
477478

478479
crate::const_eval::report(
479480
*ecx.tcx,

compiler/rustc_const_eval/src/interpret/memory.rs

+46-18
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,21 @@ pub enum AllocKind {
7272
Dead,
7373
}
7474

75+
/// Metadata about an `AllocId`.
76+
#[derive(Copy, Clone, PartialEq, Debug)]
77+
pub struct AllocInfo {
78+
pub size: Size,
79+
pub align: Align,
80+
pub kind: AllocKind,
81+
pub mutbl: Mutability,
82+
}
83+
84+
impl AllocInfo {
85+
fn new(size: Size, align: Align, kind: AllocKind, mutbl: Mutability) -> Self {
86+
Self { size, align, kind, mutbl }
87+
}
88+
}
89+
7590
/// The value of a function pointer.
7691
#[derive(Debug, Copy, Clone)]
7792
pub enum FnVal<'tcx, Other> {
@@ -524,17 +539,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
524539
match self.ptr_try_get_alloc_id(ptr, 0) {
525540
Err(addr) => is_offset_misaligned(addr, align),
526541
Ok((alloc_id, offset, _prov)) => {
527-
let (_size, alloc_align, kind, _mutbl) = self.get_alloc_info(alloc_id);
528-
if let Some(misalign) =
529-
M::alignment_check(self, alloc_id, alloc_align, kind, offset, align)
530-
{
542+
let alloc_info = self.get_alloc_info(alloc_id);
543+
if let Some(misalign) = M::alignment_check(
544+
self,
545+
alloc_id,
546+
alloc_info.align,
547+
alloc_info.kind,
548+
offset,
549+
align,
550+
) {
531551
Some(misalign)
532552
} else if M::Provenance::OFFSET_IS_ADDR {
533553
is_offset_misaligned(ptr.addr().bytes(), align)
534554
} else {
535555
// Check allocation alignment and offset alignment.
536-
if alloc_align.bytes() < align.bytes() {
537-
Some(Misalignment { has: alloc_align, required: align })
556+
if alloc_info.align.bytes() < align.bytes() {
557+
Some(Misalignment { has: alloc_info.align, required: align })
538558
} else {
539559
is_offset_misaligned(offset.bytes(), align)
540560
}
@@ -818,19 +838,24 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
818838

819839
/// Obtain the size and alignment of an allocation, even if that allocation has
820840
/// been deallocated.
821-
pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind, Mutability) {
841+
pub fn get_alloc_info(&self, id: AllocId) -> AllocInfo {
822842
// # Regular allocations
823843
// Don't use `self.get_raw` here as that will
824844
// a) cause cycles in case `id` refers to a static
825845
// b) duplicate a global's allocation in miri
826846
if let Some((_, alloc)) = self.memory.alloc_map.get(id) {
827-
return (alloc.size(), alloc.align, AllocKind::LiveData, alloc.mutability);
847+
return AllocInfo::new(
848+
alloc.size(),
849+
alloc.align,
850+
AllocKind::LiveData,
851+
alloc.mutability,
852+
);
828853
}
829854

830855
// # Function pointers
831856
// (both global from `alloc_map` and local from `extra_fn_ptr_map`)
832857
if self.get_fn_alloc(id).is_some() {
833-
return (Size::ZERO, Align::ONE, AllocKind::Function, Mutability::Not);
858+
return AllocInfo::new(Size::ZERO, Align::ONE, AllocKind::Function, Mutability::Not);
834859
}
835860

836861
// # Statics
@@ -852,7 +877,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
852877
// succeeds, as the query is fed at DefId creation time, so no
853878
// evaluation actually occurs.
854879
let alloc = self.tcx.eval_static_initializer(def_id).unwrap();
855-
(alloc.0.size(), alloc.0.align, alloc.0.mutability)
880+
// Nested statics in a `static` are never interior mutable, so just use the
881+
// declared mutability, which should be equal to the allocation's mutability.
882+
assert_eq!(mutability, alloc.0.mutability);
883+
(alloc.0.size(), alloc.0.align, mutability)
856884
} else {
857885
// Use size and align of the type for everything else. We need
858886
// to do that to
@@ -873,20 +901,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
873901
};
874902
(layout.size, layout.align.abi, mutability)
875903
};
876-
(size, align, AllocKind::LiveData, mutability)
904+
AllocInfo::new(size, align, AllocKind::LiveData, mutability)
877905
}
878906
Some(GlobalAlloc::Memory(alloc)) => {
879907
// Need to duplicate the logic here, because the global allocations have
880908
// different associated types than the interpreter-local ones.
881909
let alloc = alloc.inner();
882-
(alloc.size(), alloc.align, AllocKind::LiveData, alloc.mutability)
910+
AllocInfo::new(alloc.size(), alloc.align, AllocKind::LiveData, alloc.mutability)
883911
}
884912
Some(GlobalAlloc::Function { .. }) => {
885913
bug!("We already checked function pointers above")
886914
}
887915
Some(GlobalAlloc::VTable(..)) => {
888916
// No data to be accessed here. But vtables are pointer-aligned.
889-
return (
917+
return AllocInfo::new(
890918
Size::ZERO,
891919
self.tcx.data_layout.pointer_align.abi,
892920
AllocKind::VTable,
@@ -902,7 +930,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
902930
.dead_alloc_map
903931
.get(&id)
904932
.expect("deallocated pointers should all be recorded in `dead_alloc_map`");
905-
(size, align, AllocKind::Dead, Mutability::Not)
933+
AllocInfo::new(size, align, AllocKind::Dead, Mutability::Not)
906934
}
907935
}
908936
}
@@ -913,11 +941,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
913941
id: AllocId,
914942
msg: CheckInAllocMsg,
915943
) -> InterpResult<'tcx, (Size, Align)> {
916-
let (size, align, kind, _mutbl) = self.get_alloc_info(id);
917-
if matches!(kind, AllocKind::Dead) {
944+
let info = self.get_alloc_info(id);
945+
if matches!(info.kind, AllocKind::Dead) {
918946
throw_ub!(PointerUseAfterFree(id, msg))
919947
}
920-
interp_ok((size, align))
948+
interp_ok((info.size, info.align))
921949
}
922950

923951
fn get_fn_alloc(&self, id: AllocId) -> Option<FnVal<'tcx, M::ExtraFnVal>> {
@@ -1469,7 +1497,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
14691497
let ptr = scalar.to_pointer(self)?;
14701498
match self.ptr_try_get_alloc_id(ptr, 0) {
14711499
Ok((alloc_id, offset, _)) => {
1472-
let (size, _align, _kind, _mutbl) = self.get_alloc_info(alloc_id);
1500+
let size = self.get_alloc_info(alloc_id).size;
14731501
// If the pointer is out-of-bounds, it may be null.
14741502
// Note that one-past-the-end (offset == size) is still inbounds, and never null.
14751503
offset > size

compiler/rustc_const_eval/src/interpret/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub use self::intern::{
3131
};
3232
pub(crate) use self::intrinsics::eval_nullary_intrinsic;
3333
pub use self::machine::{AllocMap, Machine, MayLeak, ReturnAction, compile_time_machine};
34-
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
34+
pub use self::memory::{AllocInfo, AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
3535
use self::operand::Operand;
3636
pub use self::operand::{ImmTy, Immediate, OpTy};
3737
pub use self::place::{MPlaceTy, MemPlaceMeta, PlaceTy, Writeable};

compiler/rustc_const_eval/src/interpret/validity.rs

+4-52
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ use rustc_middle::ty::{self, Ty};
2929
use rustc_span::symbol::{Symbol, sym};
3030
use tracing::trace;
3131

32-
use super::machine::AllocMap;
3332
use super::{
3433
AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult,
3534
MPlaceTy, Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub,
@@ -594,8 +593,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
594593
}
595594

596595
// Dangling and Mutability check.
597-
let (size, _align, alloc_kind, _mutbl) = self.ecx.get_alloc_info(alloc_id);
598-
if alloc_kind == AllocKind::Dead {
596+
let info = self.ecx.get_alloc_info(alloc_id);
597+
if info.kind == AllocKind::Dead {
599598
// This can happen for zero-sized references. We can't have *any* references to
600599
// non-existing allocations in const-eval though, interning rejects them all as
601600
// the rest of rustc isn't happy with them... so we throw an error, even though
@@ -618,7 +617,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
618617
}
619618
};
620619
// Determine what it actually points to.
621-
let alloc_actual_mutbl = mutability(self.ecx, alloc_id);
620+
let alloc_actual_mutbl = info.mutbl;
622621
// Mutable pointer to immutable memory is no good.
623622
if ptr_expected_mutbl == Mutability::Mut
624623
&& alloc_actual_mutbl == Mutability::Not
@@ -844,7 +843,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
844843
fn in_mutable_memory(&self, val: &PlaceTy<'tcx, M::Provenance>) -> bool {
845844
if let Some(mplace) = val.as_mplace_or_local().left() {
846845
if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) {
847-
mutability(self.ecx, alloc_id).is_mut()
846+
self.ecx.get_alloc_info(alloc_id).mutbl.is_mut()
848847
} else {
849848
// No memory at all.
850849
false
@@ -1016,53 +1015,6 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
10161015
}
10171016
}
10181017

1019-
/// Returns whether the allocation is mutable, and whether it's actually a static.
1020-
/// For "root" statics we look at the type to account for interior
1021-
/// mutability; for nested statics we have no type and directly use the annotated mutability.
1022-
fn mutability<'tcx>(ecx: &InterpCx<'tcx, impl Machine<'tcx>>, alloc_id: AllocId) -> Mutability {
1023-
// Let's see what kind of memory this points to.
1024-
// We're not using `try_global_alloc` since dangling pointers have already been handled.
1025-
match ecx.tcx.global_alloc(alloc_id) {
1026-
GlobalAlloc::Static(did) => {
1027-
let DefKind::Static { safety: _, mutability, nested } = ecx.tcx.def_kind(did) else {
1028-
bug!()
1029-
};
1030-
if nested {
1031-
assert!(
1032-
ecx.memory.alloc_map.get(alloc_id).is_none(),
1033-
"allocations of nested statics are already interned: {alloc_id:?}, {did:?}"
1034-
);
1035-
// Nested statics in a `static` are never interior mutable,
1036-
// so just use the declared mutability.
1037-
mutability
1038-
} else {
1039-
let mutability = match mutability {
1040-
Mutability::Not
1041-
if !ecx
1042-
.tcx
1043-
.type_of(did)
1044-
.no_bound_vars()
1045-
.expect("statics should not have generic parameters")
1046-
.is_freeze(*ecx.tcx, ty::ParamEnv::reveal_all()) =>
1047-
{
1048-
Mutability::Mut
1049-
}
1050-
_ => mutability,
1051-
};
1052-
if let Some((_, alloc)) = ecx.memory.alloc_map.get(alloc_id) {
1053-
assert_eq!(alloc.mutability, mutability);
1054-
}
1055-
mutability
1056-
}
1057-
}
1058-
GlobalAlloc::Memory(alloc) => alloc.inner().mutability,
1059-
GlobalAlloc::Function { .. } | GlobalAlloc::VTable(..) => {
1060-
// These are immutable, we better don't allow mutable pointers here.
1061-
Mutability::Not
1062-
}
1063-
}
1064-
}
1065-
10661018
impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, 'tcx, M> {
10671019
type V = PlaceTy<'tcx, M::Provenance>;
10681020

src/tools/miri/src/alloc_addresses/mod.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
134134
// entered for addresses that are not the base address, so even zero-sized
135135
// allocations will get recognized at their base address -- but all other
136136
// allocations will *not* be recognized at their "end" address.
137-
let size = ecx.get_alloc_info(alloc_id).0;
137+
let size = ecx.get_alloc_info(alloc_id).size;
138138
if offset < size.bytes() { Some(alloc_id) } else { None }
139139
}
140140
}?;
@@ -157,25 +157,25 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
157157
) -> InterpResult<'tcx, u64> {
158158
let ecx = self.eval_context_ref();
159159
let mut rng = ecx.machine.rng.borrow_mut();
160-
let (size, align, kind, _mutbl) = ecx.get_alloc_info(alloc_id);
160+
let info = ecx.get_alloc_info(alloc_id);
161161
// This is either called immediately after allocation (and then cached), or when
162162
// adjusting `tcx` pointers (which never get freed). So assert that we are looking
163163
// at a live allocation. This also ensures that we never re-assign an address to an
164164
// allocation that previously had an address, but then was freed and the address
165165
// information was removed.
166-
assert!(!matches!(kind, AllocKind::Dead));
166+
assert!(!matches!(info.kind, AllocKind::Dead));
167167

168168
// This allocation does not have a base address yet, pick or reuse one.
169169
if ecx.machine.native_lib.is_some() {
170170
// In native lib mode, we use the "real" address of the bytes for this allocation.
171171
// This ensures the interpreted program and native code have the same view of memory.
172-
let base_ptr = match kind {
172+
let base_ptr = match info.kind {
173173
AllocKind::LiveData => {
174174
if ecx.tcx.try_get_global_alloc(alloc_id).is_some() {
175175
// For new global allocations, we always pre-allocate the memory to be able use the machine address directly.
176-
let prepared_bytes = MiriAllocBytes::zeroed(size, align)
176+
let prepared_bytes = MiriAllocBytes::zeroed(info.size, info.align)
177177
.unwrap_or_else(|| {
178-
panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes")
178+
panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes", size = info.size)
179179
});
180180
let ptr = prepared_bytes.as_ptr();
181181
// Store prepared allocation space to be picked up for use later.
@@ -204,7 +204,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
204204
}
205205
// We are not in native lib mode, so we control the addresses ourselves.
206206
if let Some((reuse_addr, clock)) =
207-
global_state.reuse.take_addr(&mut *rng, size, align, memory_kind, ecx.active_thread())
207+
global_state.reuse.take_addr(&mut *rng, info.size, info.align, memory_kind, ecx.active_thread())
208208
{
209209
if let Some(clock) = clock {
210210
ecx.acquire_clock(&clock);
@@ -220,14 +220,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
220220
.next_base_addr
221221
.checked_add(slack)
222222
.ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
223-
let base_addr = align_addr(base_addr, align.bytes());
223+
let base_addr = align_addr(base_addr, info.align.bytes());
224224

225225
// Remember next base address. If this allocation is zero-sized, leave a gap of at
226226
// least 1 to avoid two allocations having the same base address. (The logic in
227227
// `alloc_id_from_addr` assumes unique addresses, and different function/vtable pointers
228228
// need to be distinguishable!)
229229
global_state.next_base_addr = base_addr
230-
.checked_add(max(size.bytes(), 1))
230+
.checked_add(max(info.size.bytes(), 1))
231231
.ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
232232
// Even if `Size` didn't overflow, we might still have filled up the address space.
233233
if global_state.next_base_addr > ecx.target_usize_max() {

src/tools/miri/src/borrow_tracker/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
363363
// If it does exist, then we have the guarantee that the
364364
// pointer is readable, and the implicit read access inserted
365365
// will never cause UB on the pointer itself.
366-
let (_, _, kind, _mutbl) = this.get_alloc_info(*alloc_id);
366+
let kind = this.get_alloc_info(*alloc_id).kind;
367367
if matches!(kind, AllocKind::LiveData) {
368368
let alloc_extra = this.get_alloc_extra(*alloc_id)?; // can still fail for `extern static`
369369
let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap();

src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
626626
return interp_ok(())
627627
};
628628

629-
let (_size, _align, alloc_kind, _mutbl) = this.get_alloc_info(alloc_id);
629+
let alloc_kind = this.get_alloc_info(alloc_id).kind;
630630
match alloc_kind {
631631
AllocKind::LiveData => {
632632
// This should have alloc_extra data, but `get_alloc_extra` can still fail
@@ -1017,7 +1017,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
10171017
// Function pointers and dead objects don't have an alloc_extra so we ignore them.
10181018
// This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks.
10191019
// NOT using `get_alloc_extra_mut` since this might be a read-only allocation!
1020-
let (_size, _align, kind, _mutbl) = this.get_alloc_info(alloc_id);
1020+
let kind = this.get_alloc_info(alloc_id).kind;
10211021
match kind {
10221022
AllocKind::LiveData => {
10231023
// This should have alloc_extra data, but `get_alloc_extra` can still fail

src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
274274
.insert(new_tag, protect);
275275
}
276276

277-
let alloc_kind = this.get_alloc_info(alloc_id).2;
277+
let alloc_kind = this.get_alloc_info(alloc_id).kind;
278278
if !matches!(alloc_kind, AllocKind::LiveData) {
279279
assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here
280280
// There's not actually any bytes here where accesses could even be tracked.
@@ -538,7 +538,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
538538
// Function pointers and dead objects don't have an alloc_extra so we ignore them.
539539
// This is okay because accessing them is UB anyway, no need for any Tree Borrows checks.
540540
// NOT using `get_alloc_extra_mut` since this might be a read-only allocation!
541-
let (_size, _align, kind, _mutbl) = this.get_alloc_info(alloc_id);
541+
let kind = this.get_alloc_info(alloc_id).kind;
542542
match kind {
543543
AllocKind::LiveData => {
544544
// This should have alloc_extra data, but `get_alloc_extra` can still fail

0 commit comments

Comments
 (0)