Rollup merge of #63076 - RalfJung:miri-fn-ptr-alloc-size, r=oli-obk
Miri: fix determining size of an "extra function" allocation Fixes [a bug](https://github.com/rust-lang/miri/pull/862) introduced by https://github.com/rust-lang/rust/pull/62982. Best reviewed commit-by-commit. r? @oli-obk
This commit is contained in:
commit
5922a1916b
2 changed files with 52 additions and 38 deletions
|
@ -54,6 +54,16 @@ pub trait AllocMap<K: Hash + Eq, V> {
|
||||||
k: K,
|
k: K,
|
||||||
vacant: impl FnOnce() -> Result<V, E>
|
vacant: impl FnOnce() -> Result<V, E>
|
||||||
) -> Result<&mut V, E>;
|
) -> Result<&mut V, E>;
|
||||||
|
|
||||||
|
/// Read-only lookup.
|
||||||
|
fn get(&self, k: K) -> Option<&V> {
|
||||||
|
self.get_or(k, || Err(())).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mutable lookup.
|
||||||
|
fn get_mut(&mut self, k: K) -> Option<&mut V> {
|
||||||
|
self.get_mut_or(k, || Err(())).ok()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Methods of this trait signifies a point where CTFE evaluation would fail
|
/// Methods of this trait signifies a point where CTFE evaluation would fail
|
||||||
|
|
|
@ -535,48 +535,52 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
||||||
id: AllocId,
|
id: AllocId,
|
||||||
liveness: AllocCheck,
|
liveness: AllocCheck,
|
||||||
) -> InterpResult<'static, (Size, Align)> {
|
) -> InterpResult<'static, (Size, Align)> {
|
||||||
|
// # Regular allocations
|
||||||
// Don't use `self.get` here as that will
|
// Don't use `self.get` here as that will
|
||||||
// a) cause cycles in case `id` refers to a static
|
// a) cause cycles in case `id` refers to a static
|
||||||
// b) duplicate a static's allocation in miri
|
// b) duplicate a static's allocation in miri
|
||||||
match self.alloc_map.get_or(id, || Err(())) {
|
if let Some((_, alloc)) = self.alloc_map.get(id) {
|
||||||
Ok((_, alloc)) => Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)),
|
return Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align));
|
||||||
Err(()) => {
|
}
|
||||||
// Not a local allocation, check the global `tcx.alloc_map`.
|
|
||||||
|
|
||||||
// Can't do this in the match argument, we may get cycle errors since the lock would
|
// # Function pointers
|
||||||
// be held throughout the match.
|
// (both global from `alloc_map` and local from `extra_fn_ptr_map`)
|
||||||
let alloc = self.tcx.alloc_map.lock().get(id);
|
if let Ok(_) = self.get_fn_alloc(id) {
|
||||||
match alloc {
|
return if let AllocCheck::Dereferencable = liveness {
|
||||||
Some(GlobalAlloc::Static(did)) => {
|
// The caller requested no function pointers.
|
||||||
// Use size and align of the type.
|
err!(DerefFunctionPointer)
|
||||||
let ty = self.tcx.type_of(did);
|
} else {
|
||||||
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
|
Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
|
||||||
Ok((layout.size, layout.align.abi))
|
};
|
||||||
},
|
}
|
||||||
Some(GlobalAlloc::Memory(alloc)) =>
|
|
||||||
// Need to duplicate the logic here, because the global allocations have
|
// # Statics
|
||||||
// different associated types than the interpreter-local ones.
|
// Can't do this in the match argument, we may get cycle errors since the lock would
|
||||||
Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)),
|
// be held throughout the match.
|
||||||
Some(GlobalAlloc::Function(_)) => {
|
let alloc = self.tcx.alloc_map.lock().get(id);
|
||||||
if let AllocCheck::Dereferencable = liveness {
|
match alloc {
|
||||||
// The caller requested no function pointers.
|
Some(GlobalAlloc::Static(did)) => {
|
||||||
err!(DerefFunctionPointer)
|
// Use size and align of the type.
|
||||||
} else {
|
let ty = self.tcx.type_of(did);
|
||||||
Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
|
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
|
||||||
}
|
Ok((layout.size, layout.align.abi))
|
||||||
},
|
},
|
||||||
// The rest must be dead.
|
Some(GlobalAlloc::Memory(alloc)) =>
|
||||||
None => if let AllocCheck::MaybeDead = liveness {
|
// Need to duplicate the logic here, because the global allocations have
|
||||||
// Deallocated pointers are allowed, we should be able to find
|
// different associated types than the interpreter-local ones.
|
||||||
// them in the map.
|
Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align)),
|
||||||
Ok(*self.dead_alloc_map.get(&id)
|
Some(GlobalAlloc::Function(_)) =>
|
||||||
.expect("deallocated pointers should all be recorded in \
|
bug!("We already checked function pointers above"),
|
||||||
`dead_alloc_map`"))
|
// The rest must be dead.
|
||||||
} else {
|
None => if let AllocCheck::MaybeDead = liveness {
|
||||||
err!(DanglingPointerDeref)
|
// Deallocated pointers are allowed, we should be able to find
|
||||||
},
|
// them in the map.
|
||||||
}
|
Ok(*self.dead_alloc_map.get(&id)
|
||||||
}
|
.expect("deallocated pointers should all be recorded in \
|
||||||
|
`dead_alloc_map`"))
|
||||||
|
} else {
|
||||||
|
err!(DanglingPointerDeref)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue