Deduplicate logic for checking the mutability of allocations
This commit is contained in:
parent
d87e9636d5
commit
140c9e10bb
1 changed files with 75 additions and 79 deletions
|
@ -10,6 +10,7 @@ use std::num::NonZero;
|
||||||
use either::{Left, Right};
|
use either::{Left, Right};
|
||||||
|
|
||||||
use hir::def::DefKind;
|
use hir::def::DefKind;
|
||||||
|
use hir::def_id::DefId;
|
||||||
use rustc_ast::Mutability;
|
use rustc_ast::Mutability;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -449,23 +450,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||||
// `!` is a ZST and we want to validate it.
|
// `!` is a ZST and we want to validate it.
|
||||||
if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr()) {
|
if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr()) {
|
||||||
let mut skip_recursive_check = false;
|
let mut skip_recursive_check = false;
|
||||||
// Let's see what kind of memory this points to.
|
let (alloc_actual_mutbl, is_static) = mutability(self.ecx, alloc_id);
|
||||||
// `unwrap` since dangling pointers have already been handled.
|
if let Some((did, nested)) = is_static {
|
||||||
let alloc_kind = self.ecx.tcx.try_get_global_alloc(alloc_id).unwrap();
|
|
||||||
let alloc_actual_mutbl = match alloc_kind {
|
|
||||||
GlobalAlloc::Static(did) => {
|
|
||||||
// Special handling for pointers to statics (irrespective of their type).
|
// Special handling for pointers to statics (irrespective of their type).
|
||||||
assert!(!self.ecx.tcx.is_thread_local_static(did));
|
assert!(!self.ecx.tcx.is_thread_local_static(did));
|
||||||
assert!(self.ecx.tcx.is_static(did));
|
assert!(self.ecx.tcx.is_static(did));
|
||||||
let DefKind::Static { mutability, nested } = self.ecx.tcx.def_kind(did)
|
|
||||||
else {
|
|
||||||
bug!()
|
|
||||||
};
|
|
||||||
// Mode-specific checks
|
// Mode-specific checks
|
||||||
match self.ctfe_mode {
|
match self.ctfe_mode {
|
||||||
Some(
|
Some(
|
||||||
CtfeValidationMode::Static { .. }
|
CtfeValidationMode::Static { .. } | CtfeValidationMode::Promoted { .. },
|
||||||
| CtfeValidationMode::Promoted { .. },
|
|
||||||
) => {
|
) => {
|
||||||
// We skip recursively checking other statics. These statics must be sound by
|
// We skip recursively checking other statics. These statics must be sound by
|
||||||
// themselves, and the only way to get broken statics here is by using
|
// themselves, and the only way to get broken statics here is by using
|
||||||
|
@ -489,33 +482,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
// Return alloc mutability. 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.
|
|
||||||
if nested {
|
|
||||||
mutability
|
|
||||||
} else {
|
|
||||||
match mutability {
|
|
||||||
Mutability::Not
|
|
||||||
if !self
|
|
||||||
.ecx
|
|
||||||
.tcx
|
|
||||||
.type_of(did)
|
|
||||||
.no_bound_vars()
|
|
||||||
.expect("statics should not have generic parameters")
|
|
||||||
.is_freeze(*self.ecx.tcx, ty::ParamEnv::reveal_all()) =>
|
|
||||||
{
|
|
||||||
Mutability::Mut
|
|
||||||
}
|
}
|
||||||
_ => mutability,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GlobalAlloc::Memory(alloc) => alloc.inner().mutability,
|
|
||||||
GlobalAlloc::Function(..) | GlobalAlloc::VTable(..) => {
|
|
||||||
// These are immutable, we better don't allow mutable pointers here.
|
|
||||||
Mutability::Not
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Mutability check.
|
// Mutability check.
|
||||||
// If this allocation has size zero, there is no actual mutability here.
|
// If this allocation has size zero, there is no actual mutability here.
|
||||||
let (size, _align, _alloc_kind) = self.ecx.get_alloc_info(alloc_id);
|
let (size, _align, _alloc_kind) = self.ecx.get_alloc_info(alloc_id);
|
||||||
|
@ -714,28 +682,56 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||||
fn in_mutable_memory(&self, op: &OpTy<'tcx, M::Provenance>) -> bool {
|
fn in_mutable_memory(&self, op: &OpTy<'tcx, M::Provenance>) -> bool {
|
||||||
if let Some(mplace) = op.as_mplace_or_imm().left() {
|
if let Some(mplace) = op.as_mplace_or_imm().left() {
|
||||||
if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) {
|
if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) {
|
||||||
let mutability = match self.ecx.tcx.global_alloc(alloc_id) {
|
return mutability(self.ecx, alloc_id).0.is_mut();
|
||||||
GlobalAlloc::Static(did) => {
|
|
||||||
let DefKind::Static { mutability, nested } = self.ecx.tcx.def_kind(did)
|
|
||||||
else {
|
|
||||||
bug!()
|
|
||||||
};
|
|
||||||
if nested {
|
|
||||||
mutability
|
|
||||||
} else {
|
|
||||||
self.ecx.memory.alloc_map.get(alloc_id).unwrap().1.mutability
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GlobalAlloc::Memory(alloc) => alloc.inner().mutability,
|
|
||||||
_ => span_bug!(self.ecx.tcx.span, "not a memory allocation"),
|
|
||||||
};
|
|
||||||
return mutability == Mutability::Mut;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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<'mir, 'tcx: 'mir>(
|
||||||
|
ecx: &InterpCx<'mir, 'tcx, impl Machine<'mir, 'tcx>>,
|
||||||
|
alloc_id: AllocId,
|
||||||
|
) -> (Mutability, Option<(DefId, bool)>) {
|
||||||
|
// 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 { mutability, nested } = ecx.tcx.def_kind(did) else { bug!() };
|
||||||
|
let mutability = if nested {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
(mutability, Some((did, nested)))
|
||||||
|
}
|
||||||
|
GlobalAlloc::Memory(alloc) => (alloc.inner().mutability, None),
|
||||||
|
GlobalAlloc::Function(..) | GlobalAlloc::VTable(..) => {
|
||||||
|
// These are immutable, we better don't allow mutable pointers here.
|
||||||
|
(Mutability::Not, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
|
||||||
for ValidityVisitor<'rt, 'mir, 'tcx, M>
|
for ValidityVisitor<'rt, 'mir, 'tcx, M>
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue