@@ -594,13 +594,35 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
594
594
Ok ( true )
595
595
}
596
596
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...
601
601
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) ?;
604
626
Ok ( true )
605
627
}
606
628
ty:: FnPtr ( _sig) => {
0 commit comments