Skip to content

Commit b094116

Browse files
committed
interpret: refactor allocation info query
We now have an infallible function that also tells us which kind of allocation we are talking about. Also we do longer have to distinguish between data and function allocations for liveness.
1 parent 1aabd8a commit b094116

File tree

2 files changed

+34
-51
lines changed

2 files changed

+34
-51
lines changed

compiler/rustc_const_eval/src/interpret/memory.rs

+33-50
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,14 @@ impl<T: fmt::Display> fmt::Display for MemoryKind<T> {
5656
}
5757
}
5858

59-
/// Used by `get_size_and_align` to indicate whether the allocation needs to be live.
60-
#[derive(Debug, Copy, Clone)]
61-
pub enum AllocCheck {
62-
/// Allocation must be live and not a function pointer.
63-
Dereferenceable,
64-
/// Allocations needs to be live, but may be a function pointer.
65-
Live,
66-
/// Allocation may be dead.
67-
MaybeDead,
59+
/// The return value of `get_alloc_info` indicates the "kind" of the allocation.
60+
pub enum AllocKind {
61+
/// A regular live data allocation.
62+
LiveData,
63+
/// A function allocation (that fn ptrs point to).
64+
Function,
65+
/// A dead allocation.
66+
Dead,
6867
}
6968

7069
/// The value of a function pointer.
@@ -360,8 +359,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
360359
align,
361360
CheckInAllocMsg::MemoryAccessTest,
362361
|alloc_id, offset, tag| {
363-
let (size, align) =
364-
self.get_alloc_size_and_align(alloc_id, AllocCheck::Dereferenceable)?;
362+
let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
365363
Ok((size, align, (alloc_id, offset, tag)))
366364
},
367365
)
@@ -379,15 +377,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
379377
msg: CheckInAllocMsg,
380378
) -> InterpResult<'tcx> {
381379
self.check_and_deref_ptr(ptr, size, Some(align), msg, |alloc_id, _, _| {
382-
let check = match msg {
383-
CheckInAllocMsg::DerefTest | CheckInAllocMsg::MemoryAccessTest => {
384-
AllocCheck::Dereferenceable
385-
}
386-
CheckInAllocMsg::PointerArithmeticTest
387-
| CheckInAllocMsg::OffsetFromTest
388-
| CheckInAllocMsg::InboundsTest => AllocCheck::Live,
389-
};
390-
let (size, align) = self.get_alloc_size_and_align(alloc_id, check)?;
380+
let (size, align) = self.get_live_alloc_size_and_align(alloc_id)?;
391381
Ok((size, align, ()))
392382
})?;
393383
Ok(())
@@ -655,30 +645,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
655645

656646
/// Obtain the size and alignment of an allocation, even if that allocation has
657647
/// been deallocated.
658-
///
659-
/// If `liveness` is `AllocCheck::MaybeDead`, this function always returns `Ok`.
660-
pub fn get_alloc_size_and_align(
661-
&self,
662-
id: AllocId,
663-
liveness: AllocCheck,
664-
) -> InterpResult<'tcx, (Size, Align)> {
648+
pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind) {
665649
// # Regular allocations
666650
// Don't use `self.get_raw` here as that will
667651
// a) cause cycles in case `id` refers to a static
668652
// b) duplicate a global's allocation in miri
669653
if let Some((_, alloc)) = self.memory.alloc_map.get(id) {
670-
return Ok((alloc.size(), alloc.align));
654+
return (alloc.size(), alloc.align, AllocKind::LiveData);
671655
}
672656

673657
// # Function pointers
674658
// (both global from `alloc_map` and local from `extra_fn_ptr_map`)
675659
if self.get_fn_alloc(id).is_some() {
676-
return if let AllocCheck::Dereferenceable = liveness {
677-
// The caller requested no function pointers.
678-
throw_ub!(DerefFunctionPointer(id))
679-
} else {
680-
Ok((Size::ZERO, Align::ONE))
681-
};
660+
return (Size::ZERO, Align::ONE, AllocKind::Function);
682661
}
683662

684663
// # Statics
@@ -690,32 +669,38 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
690669
// Use size and align of the type.
691670
let ty = self.tcx.type_of(did);
692671
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
693-
Ok((layout.size, layout.align.abi))
672+
(layout.size, layout.align.abi, AllocKind::LiveData)
694673
}
695674
Some(GlobalAlloc::Memory(alloc)) => {
696675
// Need to duplicate the logic here, because the global allocations have
697676
// different associated types than the interpreter-local ones.
698677
let alloc = alloc.inner();
699-
Ok((alloc.size(), alloc.align))
678+
(alloc.size(), alloc.align, AllocKind::LiveData)
700679
}
701680
Some(GlobalAlloc::Function(_)) => bug!("We already checked function pointers above"),
702681
// The rest must be dead.
703682
None => {
704-
if let AllocCheck::MaybeDead = liveness {
705-
// Deallocated pointers are allowed, we should be able to find
706-
// them in the map.
707-
Ok(*self
708-
.memory
709-
.dead_alloc_map
710-
.get(&id)
711-
.expect("deallocated pointers should all be recorded in `dead_alloc_map`"))
712-
} else {
713-
throw_ub!(PointerUseAfterFree(id))
714-
}
683+
// Deallocated pointers are allowed, we should be able to find
684+
// them in the map.
685+
let (size, align) = *self
686+
.memory
687+
.dead_alloc_map
688+
.get(&id)
689+
.expect("deallocated pointers should all be recorded in `dead_alloc_map`");
690+
(size, align, AllocKind::Dead)
715691
}
716692
}
717693
}
718694

695+
/// Obtain the size and alignment of a live allocation.
696+
pub fn get_live_alloc_size_and_align(&self, id: AllocId) -> InterpResult<'tcx, (Size, Align)> {
697+
let (size, align, kind) = self.get_alloc_info(id);
698+
if matches!(kind, AllocKind::Dead) {
699+
throw_ub!(PointerUseAfterFree(id))
700+
}
701+
Ok((size, align))
702+
}
703+
719704
fn get_fn_alloc(&self, id: AllocId) -> Option<FnVal<'tcx, M::ExtraFnVal>> {
720705
if let Some(extra) = self.memory.extra_fn_ptr_map.get(&id) {
721706
Some(FnVal::Other(*extra))
@@ -1187,9 +1172,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
11871172
let ptr = self.scalar_to_ptr(scalar)?;
11881173
match self.ptr_try_get_alloc_id(ptr) {
11891174
Ok((alloc_id, offset, _)) => {
1190-
let (size, _align) = self
1191-
.get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead)
1192-
.expect("alloc info with MaybeDead cannot fail");
1175+
let (size, _align, _kind) = self.get_alloc_info(alloc_id);
11931176
// If the pointer is out-of-bounds, it may be null.
11941177
// Note that one-past-the-end (offset == size) is still inbounds, and never null.
11951178
offset > size

compiler/rustc_const_eval/src/interpret/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub use self::eval_context::{
2323
};
2424
pub use self::intern::{intern_const_alloc_recursive, InternKind};
2525
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
26-
pub use self::memory::{AllocCheck, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
26+
pub use self::memory::{AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
2727
pub use self::operand::{ImmTy, Immediate, OpTy, Operand};
2828
pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy};
2929
pub use self::validity::{CtfeValidationMode, RefTracking};

0 commit comments

Comments
 (0)