diff options
| author | Ralf Jung <post@ralfj.de> | 2022-07-03 11:29:49 -0400 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2022-07-03 22:42:50 -0400 |
| commit | 7fc77806d4f66819cf9d7ebd53a3338686c08b7d (patch) | |
| tree | b55790741997f2b71f21043bf4e8d73e26d40f07 | |
| parent | b04bfb4aea99436a62f6a98056e805eb9b0629cc (diff) | |
| download | rust-7fc77806d4f66819cf9d7ebd53a3338686c08b7d.tar.gz rust-7fc77806d4f66819cf9d7ebd53a3338686c08b7d.zip | |
fix interpreter validity check on Box
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/validity.rs | 34 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/lib.rs | 1 |
2 files changed, 29 insertions, 6 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 847694cbd10..600d25548d4 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -594,13 +594,35 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' Ok(true) } ty::Adt(def, ..) if def.is_box() => { - let unique = self.ecx.operand_field(value, 0)?; - let nonnull = self.ecx.operand_field(&unique, 0)?; - let ptr = self.ecx.operand_field(&nonnull, 0)?; - self.check_safe_pointer(&ptr, "box")?; + // Box is special, very special. We carefully assert all the assumptions we make + // here; if this needs to be adjusted, remember to also adjust all the other + // visitors -- in particular the Stacked Borrows retagging visitor in Miri. + // Did I mention that this is a gross hack? Anyway... - // Check other fields of Box - self.walk_value(value)?; + // `Box` has two fields: the pointer we care about, and the allocator. + assert_eq!(value.layout.fields.count(), 2, "`Box` must have exactly 2 fields"); + let (unique_ptr, alloc) = + (self.ecx.operand_field(value, 0)?, self.ecx.operand_field(value, 1)?); + // Unfortunately there is some type junk in the way here: `unique_ptr` is a `Unique`... + // (which means another 2 fields, the second of which is a `PhantomData`) + assert_eq!(unique_ptr.layout.fields.count(), 2); + let (nonnull_ptr, phantom) = ( + self.ecx.operand_field(&unique_ptr, 0)?, + self.ecx.operand_field(&unique_ptr, 1)?, + ); + assert!( + phantom.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()), + "2nd field of `Unique` should be PhantomData but is {:?}", + phantom.layout.ty, + ); + // ... that contains a `NonNull`... (gladly, only a single field here) + assert_eq!(nonnull_ptr.layout.fields.count(), 1); + let raw_ptr = self.ecx.operand_field(&nonnull_ptr, 0)?; // the actual raw ptr + // ... whose only field finally is a raw ptr we can dereference. + self.check_safe_pointer(&raw_ptr, "box")?; + // The second `Box` field is the allocator, which we recursively check for validity + // like in regular structs. + self.walk_value(&alloc)?; Ok(true) } ty::FnPtr(_sig) => { diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 5bf91879066..2d42ae236ad 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -21,6 +21,7 @@ Rust MIR: a lowered representation of Rust. #![feature(trusted_step)] #![feature(try_blocks)] #![feature(yeet_expr)] +#![feature(is_some_with)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] |
