make return type of get_alloc_info a struct, and reduce some code dup… · rust-lang/rust@4a54ec8 (original) (raw)
`@@ -14,10 +14,9 @@ use std::{fmt, mem, ptr};
`
14
14
`use rustc_abi::{Align, HasDataLayout, Size};
`
15
15
`use rustc_ast::Mutability;
`
16
16
`use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
`
17
``
`-
use rustc_hir::def::DefKind;
`
18
17
`use rustc_middle::bug;
`
19
18
`use rustc_middle::mir::display_allocation;
`
20
``
`-
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
`
``
19
`+
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
`
21
20
`use tracing::{debug, instrument, trace};
`
22
21
``
23
22
`use super::{
`
`@@ -72,6 +71,21 @@ pub enum AllocKind {
`
72
71
`Dead,
`
73
72
`}
`
74
73
``
``
74
`` +
/// Metadata about an AllocId
.
``
``
75
`+
#[derive(Copy, Clone, PartialEq, Debug)]
`
``
76
`+
pub struct AllocInfo {
`
``
77
`+
pub size: Size,
`
``
78
`+
pub align: Align,
`
``
79
`+
pub kind: AllocKind,
`
``
80
`+
pub mutbl: Mutability,
`
``
81
`+
}
`
``
82
+
``
83
`+
impl AllocInfo {
`
``
84
`+
fn new(size: Size, align: Align, kind: AllocKind, mutbl: Mutability) -> Self {
`
``
85
`+
Self { size, align, kind, mutbl }
`
``
86
`+
}
`
``
87
`+
}
`
``
88
+
75
89
`/// The value of a function pointer.
`
76
90
`#[derive(Debug, Copy, Clone)]
`
77
91
`pub enum FnVal<'tcx, Other> {
`
`@@ -524,17 +538,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
`
524
538
`match self.ptr_try_get_alloc_id(ptr, 0) {
`
525
539
`Err(addr) => is_offset_misaligned(addr, align),
`
526
540
`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
``
`-
{
`
``
541
`+
let alloc_info = self.get_alloc_info(alloc_id);
`
``
542
`+
if let Some(misalign) = M::alignment_check(
`
``
543
`+
self,
`
``
544
`+
alloc_id,
`
``
545
`+
alloc_info.align,
`
``
546
`+
alloc_info.kind,
`
``
547
`+
offset,
`
``
548
`+
align,
`
``
549
`+
) {
`
531
550
`Some(misalign)
`
532
551
`} else if M::Provenance::OFFSET_IS_ADDR {
`
533
552
`is_offset_misaligned(ptr.addr().bytes(), align)
`
534
553
`} else {
`
535
554
`// Check allocation alignment and offset alignment.
`
536
``
`-
if alloc_align.bytes() < align.bytes() {
`
537
``
`-
Some(Misalignment { has: alloc_align, required: align })
`
``
555
`+
if alloc_info.align.bytes() < align.bytes() {
`
``
556
`+
Some(Misalignment { has: alloc_info.align, required: align })
`
538
557
`} else {
`
539
558
`is_offset_misaligned(offset.bytes(), align)
`
540
559
`}
`
`@@ -818,93 +837,45 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
`
818
837
``
819
838
`/// Obtain the size and alignment of an allocation, even if that allocation has
`
820
839
`/// been deallocated.
`
821
``
`-
pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind, Mutability) {
`
``
840
`+
pub fn get_alloc_info(&self, id: AllocId) -> AllocInfo {
`
822
841
`// # Regular allocations
`
823
842
`` // Don't use self.get_raw
here as that will
``
824
843
`` // a) cause cycles in case id
refers to a static
``
825
844
`// b) duplicate a global's allocation in miri
`
826
845
`if let Some((_, alloc)) = self.memory.alloc_map.get(id) {
`
827
``
`-
return (alloc.size(), alloc.align, AllocKind::LiveData, alloc.mutability);
`
``
846
`+
return AllocInfo::new(
`
``
847
`+
alloc.size(),
`
``
848
`+
alloc.align,
`
``
849
`+
AllocKind::LiveData,
`
``
850
`+
alloc.mutability,
`
``
851
`+
);
`
828
852
`}
`
829
853
``
830
854
`// # Function pointers
`
831
855
`` // (both global from alloc_map
and local from extra_fn_ptr_map
)
``
832
856
`if self.get_fn_alloc(id).is_some() {
`
833
``
`-
return (Size::ZERO, Align::ONE, AllocKind::Function, Mutability::Not);
`
``
857
`+
return AllocInfo::new(Size::ZERO, Align::ONE, AllocKind::Function, Mutability::Not);
`
834
858
`}
`
835
859
``
836
``
`-
// # Statics
`
837
``
`-
// Can't do this in the match argument, we may get cycle errors since the lock would
`
838
``
`-
// be held throughout the match.
`
839
``
`-
match self.tcx.try_get_global_alloc(id) {
`
840
``
`-
Some(GlobalAlloc::Static(def_id)) => {
`
841
``
`-
// Thread-local statics do not have a constant address. They must be accessed via
`
842
``
`` -
// ThreadLocalRef
; we can never have a pointer to them as a regular constant value.
``
843
``
`-
assert!(!self.tcx.is_thread_local_static(def_id));
`
844
``
-
845
``
`-
let DefKind::Static { nested, mutability, .. } = self.tcx.def_kind(def_id) else {
`
846
``
`-
bug!("GlobalAlloc::Static is not a static")
`
847
``
`-
};
`
848
``
-
849
``
`-
let (size, align, mutability) = if nested {
`
850
``
`-
// Nested anonymous statics are untyped, so let's get their
`
851
``
`-
// size and alignment from the allocation itself. This always
`
852
``
`-
// succeeds, as the query is fed at DefId creation time, so no
`
853
``
`-
// evaluation actually occurs.
`
854
``
`-
let alloc = self.tcx.eval_static_initializer(def_id).unwrap();
`
855
``
`-
(alloc.0.size(), alloc.0.align, alloc.0.mutability)
`
856
``
`-
} else {
`
857
``
`-
// Use size and align of the type for everything else. We need
`
858
``
`-
// to do that to
`
859
``
`-
// * avoid cycle errors in case of self-referential statics,
`
860
``
`-
// * be able to get information on extern statics.
`
861
``
`-
let ty = self
`
862
``
`-
.tcx
`
863
``
`-
.type_of(def_id)
`
864
``
`-
.no_bound_vars()
`
865
``
`-
.expect("statics should not have generic parameters");
`
866
``
`-
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
`
867
``
`-
assert!(layout.is_sized());
`
868
``
`-
let mutability = match mutability {
`
869
``
`-
Mutability::Not if !ty.is_freeze(*self.tcx, ParamEnv::empty()) => {
`
870
``
`-
Mutability::Not
`
871
``
`-
}
`
872
``
`-
_ => Mutability::Mut,
`
873
``
`-
};
`
874
``
`-
(layout.size, layout.align.abi, mutability)
`
875
``
`-
};
`
876
``
`-
(size, align, AllocKind::LiveData, mutability)
`
877
``
`-
}
`
878
``
`-
Some(GlobalAlloc::Memory(alloc)) => {
`
879
``
`-
// Need to duplicate the logic here, because the global allocations have
`
880
``
`-
// different associated types than the interpreter-local ones.
`
881
``
`-
let alloc = alloc.inner();
`
882
``
`-
(alloc.size(), alloc.align, AllocKind::LiveData, alloc.mutability)
`
883
``
`-
}
`
884
``
`-
Some(GlobalAlloc::Function { .. }) => {
`
885
``
`-
bug!("We already checked function pointers above")
`
886
``
`-
}
`
887
``
`-
Some(GlobalAlloc::VTable(..)) => {
`
888
``
`-
// No data to be accessed here. But vtables are pointer-aligned.
`
889
``
`-
return (
`
890
``
`-
Size::ZERO,
`
891
``
`-
self.tcx.data_layout.pointer_align.abi,
`
892
``
`-
AllocKind::VTable,
`
893
``
`-
Mutability::Not,
`
894
``
`-
);
`
895
``
`-
}
`
896
``
`-
// The rest must be dead.
`
897
``
`-
None => {
`
898
``
`-
// Deallocated pointers are allowed, we should be able to find
`
899
``
`-
// them in the map.
`
900
``
`-
let (size, align) = *self
`
901
``
`-
.memory
`
902
``
`-
.dead_alloc_map
`
903
``
`-
.get(&id)
`
904
``
`` -
.expect("deallocated pointers should all be recorded in dead_alloc_map
");
``
905
``
`-
(size, align, AllocKind::Dead, Mutability::Not)
`
906
``
`-
}
`
``
860
`+
// # Global allocations
`
``
861
`+
if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) {
`
``
862
`+
let (size, align) = global_alloc.size_and_align(*self.tcx, self.param_env);
`
``
863
`+
let mutbl = global_alloc.mutability(*self.tcx, self.param_env);
`
``
864
`+
let kind = match global_alloc {
`
``
865
`+
GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData,
`
``
866
`+
GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"),
`
``
867
`+
GlobalAlloc::VTable { .. } => AllocKind::VTable,
`
``
868
`+
};
`
``
869
`+
return AllocInfo::new(size, align, kind, mutbl);
`
907
870
`}
`
``
871
+
``
872
`+
// # Dead pointers
`
``
873
`+
let (size, align) = *self
`
``
874
`+
.memory
`
``
875
`+
.dead_alloc_map
`
``
876
`+
.get(&id)
`
``
877
`` +
.expect("deallocated pointers should all be recorded in dead_alloc_map
");
``
``
878
`+
AllocInfo::new(size, align, AllocKind::Dead, Mutability::Not)
`
908
879
`}
`
909
880
``
910
881
`/// Obtain the size and alignment of a live allocation.
`
`@@ -913,11 +884,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
`
913
884
`id: AllocId,
`
914
885
`msg: CheckInAllocMsg,
`
915
886
`) -> InterpResult<'tcx, (Size, Align)> {
`
916
``
`-
let (size, align, kind, _mutbl) = self.get_alloc_info(id);
`
917
``
`-
if matches!(kind, AllocKind::Dead) {
`
``
887
`+
let info = self.get_alloc_info(id);
`
``
888
`+
if matches!(info.kind, AllocKind::Dead) {
`
918
889
`throw_ub!(PointerUseAfterFree(id, msg))
`
919
890
`}
`
920
``
`-
interp_ok((size, align))
`
``
891
`+
interp_ok((info.size, info.align))
`
921
892
`}
`
922
893
``
923
894
`fn get_fn_alloc(&self, id: AllocId) -> Option<FnVal<'tcx, M::ExtraFnVal>> {
`
`@@ -1469,7 +1440,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
`
1469
1440
`let ptr = scalar.to_pointer(self)?;
`
1470
1441
`match self.ptr_try_get_alloc_id(ptr, 0) {
`
1471
1442
`Ok((alloc_id, offset, _)) => {
`
1472
``
`-
let (size, _align, _kind, _mutbl) = self.get_alloc_info(alloc_id);
`
``
1443
`+
let size = self.get_alloc_info(alloc_id).size;
`
1473
1444
`// If the pointer is out-of-bounds, it may be null.
`
1474
1445
`// Note that one-past-the-end (offset == size) is still inbounds, and never null.
`
1475
1446
` offset > size
`