@@ -10,6 +10,7 @@ use std::num::NonZero;
10
10
use either:: { Left , Right } ;
11
11
12
12
use hir:: def:: DefKind ;
13
+ use hir:: def_id:: DefId ;
13
14
use rustc_ast:: Mutability ;
14
15
use rustc_data_structures:: fx:: FxHashSet ;
15
16
use rustc_hir as hir;
@@ -449,73 +450,40 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
449
450
// `!` is a ZST and we want to validate it.
450
451
if let Ok ( ( alloc_id, _offset, _prov) ) = self . ecx . ptr_try_get_alloc_id ( place. ptr ( ) ) {
451
452
let mut skip_recursive_check = false ;
452
- // Let's see what kind of memory this points to.
453
- // `unwrap` since dangling pointers have already been handled.
454
- let alloc_kind = self . ecx . tcx . try_get_global_alloc ( alloc_id) . unwrap ( ) ;
455
- let alloc_actual_mutbl = match alloc_kind {
456
- GlobalAlloc :: Static ( did) => {
457
- // Special handling for pointers to statics (irrespective of their type).
458
- assert ! ( !self . ecx. tcx. is_thread_local_static( did) ) ;
459
- assert ! ( self . ecx. tcx. is_static( did) ) ;
460
- let DefKind :: Static { mutability, nested } = self . ecx . tcx . def_kind ( did)
461
- else {
462
- bug ! ( )
463
- } ;
464
- // Mode-specific checks
465
- match self . ctfe_mode {
466
- Some (
467
- CtfeValidationMode :: Static { .. }
468
- | CtfeValidationMode :: Promoted { .. } ,
469
- ) => {
470
- // We skip recursively checking other statics. These statics must be sound by
471
- // themselves, and the only way to get broken statics here is by using
472
- // unsafe code.
473
- // The reasons we don't check other statics is twofold. For one, in all
474
- // sound cases, the static was already validated on its own, and second, we
475
- // trigger cycle errors if we try to compute the value of the other static
476
- // and that static refers back to us (potentially through a promoted).
477
- // This could miss some UB, but that's fine.
478
- // We still walk nested allocations, as they are fundamentally part of this validation run.
479
- // This means we will also recurse into nested statics of *other*
480
- // statics, even though we do not recurse into other statics directly.
481
- // That's somewhat inconsistent but harmless.
482
- skip_recursive_check = !nested;
483
- }
484
- Some ( CtfeValidationMode :: Const { .. } ) => {
485
- // We can't recursively validate `extern static`, so we better reject them.
486
- if self . ecx . tcx . is_foreign_item ( did) {
487
- throw_validation_failure ! ( self . path, ConstRefToExtern ) ;
488
- }
489
- }
490
- None => { }
453
+ let ( alloc_actual_mutbl, is_static) = mutability ( self . ecx , alloc_id) ;
454
+ if let Some ( ( did, nested) ) = is_static {
455
+ // Special handling for pointers to statics (irrespective of their type).
456
+ assert ! ( !self . ecx. tcx. is_thread_local_static( did) ) ;
457
+ assert ! ( self . ecx. tcx. is_static( did) ) ;
458
+ // Mode-specific checks
459
+ match self . ctfe_mode {
460
+ Some (
461
+ CtfeValidationMode :: Static { .. } | CtfeValidationMode :: Promoted { .. } ,
462
+ ) => {
463
+ // We skip recursively checking other statics. These statics must be sound by
464
+ // themselves, and the only way to get broken statics here is by using
465
+ // unsafe code.
466
+ // The reasons we don't check other statics is twofold. For one, in all
467
+ // sound cases, the static was already validated on its own, and second, we
468
+ // trigger cycle errors if we try to compute the value of the other static
469
+ // and that static refers back to us (potentially through a promoted).
470
+ // This could miss some UB, but that's fine.
471
+ // We still walk nested allocations, as they are fundamentally part of this validation run.
472
+ // This means we will also recurse into nested statics of *other*
473
+ // statics, even though we do not recurse into other statics directly.
474
+ // That's somewhat inconsistent but harmless.
475
+ skip_recursive_check = !nested;
491
476
}
492
- // Return alloc mutability. For "root" statics we look at the type to account for interior
493
- // mutability; for nested statics we have no type and directly use the annotated mutability.
494
- if nested {
495
- mutability
496
- } else {
497
- match mutability {
498
- Mutability :: Not
499
- if !self
500
- . ecx
501
- . tcx
502
- . type_of ( did)
503
- . no_bound_vars ( )
504
- . expect ( "statics should not have generic parameters" )
505
- . is_freeze ( * self . ecx . tcx , ty:: ParamEnv :: reveal_all ( ) ) =>
506
- {
507
- Mutability :: Mut
508
- }
509
- _ => mutability,
477
+ Some ( CtfeValidationMode :: Const { .. } ) => {
478
+ // We can't recursively validate `extern static`, so we better reject them.
479
+ if self . ecx . tcx . is_foreign_item ( did) {
480
+ throw_validation_failure ! ( self . path, ConstRefToExtern ) ;
510
481
}
511
482
}
483
+ None => { }
512
484
}
513
- GlobalAlloc :: Memory ( alloc) => alloc. inner ( ) . mutability ,
514
- GlobalAlloc :: Function ( ..) | GlobalAlloc :: VTable ( ..) => {
515
- // These are immutable, we better don't allow mutable pointers here.
516
- Mutability :: Not
517
- }
518
- } ;
485
+ }
486
+
519
487
// Mutability check.
520
488
// If this allocation has size zero, there is no actual mutability here.
521
489
let ( size, _align, _alloc_kind) = self . ecx . get_alloc_info ( alloc_id) ;
@@ -714,28 +682,56 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
714
682
fn in_mutable_memory ( & self , op : & OpTy < ' tcx , M :: Provenance > ) -> bool {
715
683
if let Some ( mplace) = op. as_mplace_or_imm ( ) . left ( ) {
716
684
if let Some ( alloc_id) = mplace. ptr ( ) . provenance . and_then ( |p| p. get_alloc_id ( ) ) {
717
- let mutability = match self . ecx . tcx . global_alloc ( alloc_id) {
718
- GlobalAlloc :: Static ( did) => {
719
- let DefKind :: Static { mutability, nested } = self . ecx . tcx . def_kind ( did)
720
- else {
721
- bug ! ( )
722
- } ;
723
- if nested {
724
- mutability
725
- } else {
726
- self . ecx . memory . alloc_map . get ( alloc_id) . unwrap ( ) . 1 . mutability
727
- }
728
- }
729
- GlobalAlloc :: Memory ( alloc) => alloc. inner ( ) . mutability ,
730
- _ => span_bug ! ( self . ecx. tcx. span, "not a memory allocation" ) ,
731
- } ;
732
- return mutability == Mutability :: Mut ;
685
+ return mutability ( self . ecx , alloc_id) . 0 . is_mut ( ) ;
733
686
}
734
687
}
735
688
false
736
689
}
737
690
}
738
691
692
+ /// Returns whether the allocation is mutable, and whether it's actually a static.
693
+ /// For "root" statics we look at the type to account for interior
694
+ /// mutability; for nested statics we have no type and directly use the annotated mutability.
695
+ fn mutability < ' mir , ' tcx : ' mir > (
696
+ ecx : & InterpCx < ' mir , ' tcx , impl Machine < ' mir , ' tcx > > ,
697
+ alloc_id : AllocId ,
698
+ ) -> ( Mutability , Option < ( DefId , bool ) > ) {
699
+ // Let's see what kind of memory this points to.
700
+ // We're not using `try_global_alloc` since dangling pointers have already been handled.
701
+ match ecx. tcx . global_alloc ( alloc_id) {
702
+ GlobalAlloc :: Static ( did) => {
703
+ let DefKind :: Static { mutability, nested } = ecx. tcx . def_kind ( did) else { bug ! ( ) } ;
704
+ let mutability = if nested {
705
+ mutability
706
+ } else {
707
+ let mutability = match mutability {
708
+ Mutability :: Not
709
+ if !ecx
710
+ . tcx
711
+ . type_of ( did)
712
+ . no_bound_vars ( )
713
+ . expect ( "statics should not have generic parameters" )
714
+ . is_freeze ( * ecx. tcx , ty:: ParamEnv :: reveal_all ( ) ) =>
715
+ {
716
+ Mutability :: Mut
717
+ }
718
+ _ => mutability,
719
+ } ;
720
+ if let Some ( ( _, alloc) ) = ecx. memory . alloc_map . get ( alloc_id) {
721
+ assert_eq ! ( alloc. mutability, mutability) ;
722
+ }
723
+ mutability
724
+ } ;
725
+ ( mutability, Some ( ( did, nested) ) )
726
+ }
727
+ GlobalAlloc :: Memory ( alloc) => ( alloc. inner ( ) . mutability , None ) ,
728
+ GlobalAlloc :: Function ( ..) | GlobalAlloc :: VTable ( ..) => {
729
+ // These are immutable, we better don't allow mutable pointers here.
730
+ ( Mutability :: Not , None )
731
+ }
732
+ }
733
+ }
734
+
739
735
impl < ' rt , ' mir , ' tcx : ' mir , M : Machine < ' mir , ' tcx > > ValueVisitor < ' mir , ' tcx , M >
740
736
for ValidityVisitor < ' rt , ' mir , ' tcx , M >
741
737
{
0 commit comments