Skip to content

Commit 78deacc

Browse files
committed
make redundant StorageLive UB
1 parent cc03ee6 commit 78deacc

File tree

2 files changed

+16
-23
lines changed

2 files changed

+16
-23
lines changed

compiler/rustc_mir/src/interpret/eval_context.rs

+14-19
Original file line numberDiff line numberDiff line change
@@ -840,36 +840,31 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
840840
Ok(())
841841
}
842842

843-
/// Mark a storage as live, killing the previous content and returning it.
844-
/// Remember to deallocate that!
845-
pub fn storage_live(
846-
&mut self,
847-
local: mir::Local,
848-
) -> InterpResult<'tcx, LocalValue<M::PointerTag>> {
843+
/// Mark a storage as live, killing the previous content.
844+
pub fn storage_live(&mut self, local: mir::Local) -> InterpResult<'tcx> {
849845
assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
850846
trace!("{:?} is now live", local);
851847

852848
let local_val = LocalValue::Uninitialized;
853-
// StorageLive *always* kills the value that's currently stored.
854-
// However, we do not error if the variable already is live;
855-
// see <https://github.com/rust-lang/rust/issues/42371>.
856-
Ok(mem::replace(&mut self.frame_mut().locals[local].value, local_val))
849+
// StorageLive expects the local to be dead, and marks it live.
850+
let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val);
851+
if !matches!(old, LocalValue::Dead) {
852+
throw_ub_format!("StorageLive on a local that was already live");
853+
}
854+
Ok(())
857855
}
858856

859-
/// Returns the old value of the local.
860-
/// Remember to deallocate that!
861-
pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue<M::PointerTag> {
857+
pub fn storage_dead(&mut self, local: mir::Local) -> InterpResult<'tcx> {
862858
assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
863859
trace!("{:?} is now dead", local);
864860

865-
mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead)
861+
// It is entirely okay for this local to be already dead (at least that's how we currently generate MIR)
862+
let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead);
863+
self.deallocate_local(old)?;
864+
Ok(())
866865
}
867866

868-
pub(super) fn deallocate_local(
869-
&mut self,
870-
local: LocalValue<M::PointerTag>,
871-
) -> InterpResult<'tcx> {
872-
// FIXME: should we tell the user that there was a local which was never written to?
867+
fn deallocate_local(&mut self, local: LocalValue<M::PointerTag>) -> InterpResult<'tcx> {
873868
if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
874869
// All locals have a backing allocation, even if the allocation is empty
875870
// due to the local having ZST type.

compiler/rustc_mir/src/interpret/step.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
9595

9696
// Mark locals as alive
9797
StorageLive(local) => {
98-
let old_val = self.storage_live(*local)?;
99-
self.deallocate_local(old_val)?;
98+
self.storage_live(*local)?;
10099
}
101100

102101
// Mark locals as dead
103102
StorageDead(local) => {
104-
let old_val = self.storage_dead(*local);
105-
self.deallocate_local(old_val)?;
103+
self.storage_dead(*local)?;
106104
}
107105

108106
// No dynamic semantics attached to `FakeRead`; MIR

0 commit comments

Comments
 (0)