Skip to content

Commit 7fc7780

Browse files
committed
fix interpreter validity check on Box
1 parent b04bfb4 commit 7fc7780

File tree

2 files changed

+29
-6
lines changed

2 files changed

+29
-6
lines changed

compiler/rustc_const_eval/src/interpret/validity.rs

+28-6
Original file line numberDiff line numberDiff line change
@@ -594,13 +594,35 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
594594
Ok(true)
595595
}
596596
ty::Adt(def, ..) if def.is_box() => {
597-
let unique = self.ecx.operand_field(value, 0)?;
598-
let nonnull = self.ecx.operand_field(&unique, 0)?;
599-
let ptr = self.ecx.operand_field(&nonnull, 0)?;
600-
self.check_safe_pointer(&ptr, "box")?;
597+
// Box is special, very special. We carefully assert all the assumptions we make
598+
// here; if this needs to be adjusted, remember to also adjust all the other
599+
// visitors -- in particular the Stacked Borrows retagging visitor in Miri.
600+
// Did I mention that this is a gross hack? Anyway...
601601

602-
// Check other fields of Box
603-
self.walk_value(value)?;
602+
// `Box` has two fields: the pointer we care about, and the allocator.
603+
assert_eq!(value.layout.fields.count(), 2, "`Box` must have exactly 2 fields");
604+
let (unique_ptr, alloc) =
605+
(self.ecx.operand_field(value, 0)?, self.ecx.operand_field(value, 1)?);
606+
// Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`...
607+
// (which means another 2 fields, the second of which is a `PhantomData`)
608+
assert_eq!(unique_ptr.layout.fields.count(), 2);
609+
let (nonnull_ptr, phantom) = (
610+
self.ecx.operand_field(&unique_ptr, 0)?,
611+
self.ecx.operand_field(&unique_ptr, 1)?,
612+
);
613+
assert!(
614+
phantom.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()),
615+
"2nd field of `Unique` should be PhantomData but is {:?}",
616+
phantom.layout.ty,
617+
);
618+
// ... that contains a `NonNull`... (gladly, only a single field here)
619+
assert_eq!(nonnull_ptr.layout.fields.count(), 1);
620+
let raw_ptr = self.ecx.operand_field(&nonnull_ptr, 0)?; // the actual raw ptr
621+
// ... whose only field finally is a raw ptr we can dereference.
622+
self.check_safe_pointer(&raw_ptr, "box")?;
623+
// The second `Box` field is the allocator, which we recursively check for validity
624+
// like in regular structs.
625+
self.walk_value(&alloc)?;
604626
Ok(true)
605627
}
606628
ty::FnPtr(_sig) => {

compiler/rustc_const_eval/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Rust MIR: a lowered representation of Rust.
2121
#![feature(trusted_step)]
2222
#![feature(try_blocks)]
2323
#![feature(yeet_expr)]
24+
#![feature(is_some_with)]
2425
#![recursion_limit = "256"]
2526
#![allow(rustc::potential_query_instability)]
2627

0 commit comments

Comments
 (0)