@@ -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;
@@ -27,9 +28,9 @@ use rustc_target::abi::{
27
28
use std:: hash:: Hash ;
28
29
29
30
use super :: {
30
- format_interp_error, machine :: AllocMap , AllocId , CheckInAllocMsg , GlobalAlloc , ImmTy ,
31
- Immediate , InterpCx , InterpResult , MPlaceTy , Machine , MemPlaceMeta , OpTy , Pointer , Projectable ,
32
- Scalar , ValueVisitor ,
31
+ format_interp_error, AllocId , CheckInAllocMsg , GlobalAlloc , ImmTy , Immediate , InterpCx ,
32
+ InterpResult , MPlaceTy , Machine , MemPlaceMeta , OpTy , Pointer , Projectable , Scalar ,
33
+ ValueVisitor ,
33
34
} ;
34
35
35
36
// for the validation errors
@@ -433,7 +434,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
433
434
throw_validation_failure ! ( self . path, PtrToUninhabited { ptr_kind, ty } )
434
435
}
435
436
// Recursive checking
436
- if let Some ( ref_tracking ) = self . ref_tracking . as_deref_mut ( ) {
437
+ if self . ref_tracking . is_some ( ) {
437
438
// Determine whether this pointer expects to be pointing to something mutable.
438
439
let ptr_expected_mutbl = match ptr_kind {
439
440
PointerKind :: Box => Mutability :: Mut ,
@@ -457,6 +458,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
457
458
// Special handling for pointers to statics (irrespective of their type).
458
459
assert ! ( !self . ecx. tcx. is_thread_local_static( did) ) ;
459
460
assert ! ( self . ecx. tcx. is_static( did) ) ;
461
+ // Return alloc mutability. For "root" statics we look at the type to account for interior
462
+ // mutability; for nested statics we have no type and directly use the annotated mutability.
463
+ let DefKind :: Static { mutability, nested } = self . ecx . tcx . def_kind ( did)
464
+ else {
465
+ bug ! ( )
466
+ } ;
460
467
// Mode-specific checks
461
468
match self . ctfe_mode {
462
469
Some (
@@ -471,7 +478,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
471
478
// trigger cycle errors if we try to compute the value of the other static
472
479
// and that static refers back to us (potentially through a promoted).
473
480
// This could miss some UB, but that's fine.
474
- skip_recursive_check = true ;
481
+ // We still walk nested allocations, as they are fundamentally part of this validation run.
482
+ skip_recursive_check = !nested;
475
483
}
476
484
Some ( CtfeValidationMode :: Const { .. } ) => {
477
485
// We can't recursively validate `extern static`, so we better reject them.
@@ -481,28 +489,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
481
489
}
482
490
None => { }
483
491
}
484
- // Return alloc mutability. For "root" statics we look at the type to account for interior
485
- // mutability; for nested statics we have no type and directly use the annotated mutability.
486
- let DefKind :: Static { mutability, nested } = self . ecx . tcx . def_kind ( did)
487
- else {
488
- bug ! ( )
489
- } ;
490
- match ( mutability, nested) {
491
- ( Mutability :: Mut , _) => Mutability :: Mut ,
492
- ( Mutability :: Not , true ) => Mutability :: Not ,
493
- ( Mutability :: Not , false )
494
- if !self
495
- . ecx
496
- . tcx
497
- . type_of ( did)
498
- . no_bound_vars ( )
499
- . expect ( "statics should not have generic parameters" )
500
- . is_freeze ( * self . ecx . tcx , ty:: ParamEnv :: reveal_all ( ) ) =>
501
- {
502
- Mutability :: Mut
503
- }
504
- ( Mutability :: Not , false ) => Mutability :: Not ,
505
- }
492
+ self . static_mutability ( mutability, nested, did)
506
493
}
507
494
GlobalAlloc :: Memory ( alloc) => alloc. inner ( ) . mutability ,
508
495
GlobalAlloc :: Function ( ..) | GlobalAlloc :: VTable ( ..) => {
@@ -535,7 +522,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
535
522
}
536
523
}
537
524
let path = & self . path ;
538
- ref_tracking. track ( place, || {
525
+ self . ref_tracking . as_deref_mut ( ) . unwrap ( ) . track ( place, || {
539
526
// We need to clone the path anyway, make sure it gets created
540
527
// with enough space for the additional `Deref`.
541
528
let mut new_path = Vec :: with_capacity ( path. len ( ) + 1 ) ;
@@ -547,6 +534,25 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
547
534
Ok ( ( ) )
548
535
}
549
536
537
+ fn static_mutability ( & self , mutability : Mutability , nested : bool , did : DefId ) -> Mutability {
538
+ match ( mutability, nested) {
539
+ ( Mutability :: Mut , _) => Mutability :: Mut ,
540
+ ( Mutability :: Not , true ) => Mutability :: Not ,
541
+ ( Mutability :: Not , false )
542
+ if !self
543
+ . ecx
544
+ . tcx
545
+ . type_of ( did)
546
+ . no_bound_vars ( )
547
+ . expect ( "statics should not have generic parameters" )
548
+ . is_freeze ( * self . ecx . tcx , ty:: ParamEnv :: reveal_all ( ) ) =>
549
+ {
550
+ Mutability :: Mut
551
+ }
552
+ ( Mutability :: Not , false ) => Mutability :: Not ,
553
+ }
554
+ }
555
+
550
556
/// Check if this is a value of primitive type, and if yes check the validity of the value
551
557
/// at that type. Return `true` if the type is indeed primitive.
552
558
///
@@ -599,6 +605,15 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
599
605
if place. layout . is_unsized ( ) {
600
606
self . check_wide_ptr_meta ( place. meta ( ) , place. layout ) ?;
601
607
}
608
+ if self . ref_tracking . is_some ( )
609
+ && let Some ( alloc_id) = place. ptr ( ) . provenance . and_then ( |p| p. get_alloc_id ( ) )
610
+ && self . ecx . tcx . try_get_global_alloc ( alloc_id) . is_none ( )
611
+ {
612
+ throw_validation_failure ! (
613
+ self . path,
614
+ DanglingPtrUseAfterFree { ptr_kind: PointerKind :: Ref ( Mutability :: Not ) }
615
+ )
616
+ }
602
617
Ok ( true )
603
618
}
604
619
ty:: Ref ( _, _ty, mutbl) => {
@@ -708,9 +723,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
708
723
if let Some ( mplace) = op. as_mplace_or_imm ( ) . left ( ) {
709
724
if let Some ( alloc_id) = mplace. ptr ( ) . provenance . and_then ( |p| p. get_alloc_id ( ) ) {
710
725
let mutability = match self . ecx . tcx . global_alloc ( alloc_id) {
711
- GlobalAlloc :: Static ( _) => {
712
- self . ecx . memory . alloc_map . get ( alloc_id) . unwrap ( ) . 1 . mutability
713
- }
726
+ GlobalAlloc :: Static ( id) => match self . ecx . tcx . def_kind ( id) {
727
+ DefKind :: Static { nested, mutability } => {
728
+ self . static_mutability ( mutability, nested, id)
729
+ }
730
+ _ => bug ! ( ) ,
731
+ } ,
714
732
GlobalAlloc :: Memory ( alloc) => alloc. inner ( ) . mutability ,
715
733
_ => span_bug ! ( self . ecx. tcx. span, "not a memory allocation" ) ,
716
734
} ;
@@ -975,15 +993,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
975
993
path : Vec < PathElem > ,
976
994
ref_tracking : Option < & mut RefTracking < MPlaceTy < ' tcx , M :: Provenance > , Vec < PathElem > > > ,
977
995
ctfe_mode : Option < CtfeValidationMode > ,
978
- ) -> InterpResult < ' tcx > {
996
+ ) -> InterpResult < ' tcx , Vec < PathElem > > {
979
997
trace ! ( "validate_operand_internal: {:?}, {:?}" , * op, op. layout. ty) ;
980
998
981
999
// Construct a visitor
982
1000
let mut visitor = ValidityVisitor { path, ref_tracking, ctfe_mode, ecx : self } ;
983
1001
984
1002
// Run it.
985
1003
match self . run_for_validation ( || visitor. visit_value ( op) ) {
986
- Ok ( ( ) ) => Ok ( ( ) ) ,
1004
+ Ok ( ( ) ) => Ok ( visitor . path ) ,
987
1005
// Pass through validation failures and "invalid program" issues.
988
1006
Err ( err)
989
1007
if matches ! (
@@ -1003,7 +1021,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1003
1021
}
1004
1022
}
1005
1023
}
1024
+ }
1006
1025
1026
+ impl < ' mir , ' tcx > InterpCx < ' mir , ' tcx , crate :: const_eval:: CompileTimeInterpreter < ' mir , ' tcx > > {
1007
1027
/// This function checks the data at `op` to be const-valid.
1008
1028
/// `op` is assumed to cover valid memory if it is an indirect operand.
1009
1029
/// It will error if the bits at the destination do not match the ones described by the layout.
@@ -1017,14 +1037,38 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1017
1037
#[ inline( always) ]
1018
1038
pub ( crate ) fn const_validate_operand (
1019
1039
& self ,
1020
- op : & OpTy < ' tcx , M :: Provenance > ,
1040
+ mplace : MPlaceTy < ' tcx > ,
1021
1041
path : Vec < PathElem > ,
1022
- ref_tracking : & mut RefTracking < MPlaceTy < ' tcx , M :: Provenance > , Vec < PathElem > > ,
1042
+ ref_tracking : & mut RefTracking < MPlaceTy < ' tcx > , Vec < PathElem > > ,
1023
1043
ctfe_mode : CtfeValidationMode ,
1024
1044
) -> InterpResult < ' tcx > {
1025
- self . validate_operand_internal ( op, path, Some ( ref_tracking) , Some ( ctfe_mode) )
1045
+ let prov = mplace. ptr ( ) . provenance ;
1046
+ let path = self . validate_operand_internal (
1047
+ & mplace. into ( ) ,
1048
+ path,
1049
+ Some ( ref_tracking) ,
1050
+ Some ( ctfe_mode) ,
1051
+ ) ?;
1052
+
1053
+ // There was no error, so let's check the rest of the relocations in the pointed-to allocation for
1054
+ // dangling pointers.
1055
+ if let Some ( prov) = prov
1056
+ && let Some ( GlobalAlloc :: Memory ( alloc) ) = self . tcx . try_get_global_alloc ( prov. alloc_id ( ) )
1057
+ {
1058
+ for ( _, prov) in alloc. 0 . provenance ( ) . ptrs ( ) . iter ( ) {
1059
+ if self . tcx . try_get_global_alloc ( prov. alloc_id ( ) ) . is_none ( ) {
1060
+ throw_validation_failure ! (
1061
+ path,
1062
+ DanglingPtrUseAfterFree { ptr_kind: PointerKind :: Ref ( Mutability :: Not ) }
1063
+ )
1064
+ }
1065
+ }
1066
+ }
1067
+ Ok ( ( ) )
1026
1068
}
1069
+ }
1027
1070
1071
+ impl < ' mir , ' tcx : ' mir , M : Machine < ' mir , ' tcx > > InterpCx < ' mir , ' tcx , M > {
1028
1072
/// This function checks the data at `op` to be runtime-valid.
1029
1073
/// `op` is assumed to cover valid memory if it is an indirect operand.
1030
1074
/// It will error if the bits at the destination do not match the ones described by the layout.
@@ -1034,6 +1078,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1034
1078
// still correct to not use `ctfe_mode`: that mode is for validation of the final constant
1035
1079
// value, it rules out things like `UnsafeCell` in awkward places. It also can make checking
1036
1080
// recurse through references which, for now, we don't want here, either.
1037
- self . validate_operand_internal ( op, vec ! [ ] , None , None )
1081
+ self . validate_operand_internal ( op, vec ! [ ] , None , None ) . map ( drop )
1038
1082
}
1039
1083
}
0 commit comments