@@ -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) => {
0 commit comments